commit
499905ee83
23 changed files with 529 additions and 277 deletions
|
@ -50,38 +50,27 @@ module Instructeurs
|
||||||
@current_filters = current_filters
|
@current_filters = current_filters
|
||||||
@displayed_fields_options, @displayed_fields_selected = procedure_presentation.displayed_fields_for_select
|
@displayed_fields_options, @displayed_fields_selected = procedure_presentation.displayed_fields_for_select
|
||||||
|
|
||||||
@a_suivre_dossiers = current_instructeur
|
@a_suivre_count, @suivis_count, @traites_count, @tous_count, @archives_count = current_instructeur
|
||||||
.dossiers
|
.dossiers_count_summary(groupe_instructeur_ids)
|
||||||
.for_procedure(procedure)
|
.fetch_values('a_suivre', 'suivis', 'traites', 'tous', 'archives')
|
||||||
|
|
||||||
|
dossiers_visibles = Dossier
|
||||||
|
.where(groupe_instructeur_id: groupe_instructeur_ids)
|
||||||
|
|
||||||
|
@a_suivre_dossiers = dossiers_visibles
|
||||||
.without_followers
|
.without_followers
|
||||||
.en_cours
|
.en_cours
|
||||||
|
|
||||||
@followed_dossiers = current_instructeur
|
@followed_dossiers = current_instructeur
|
||||||
.followed_dossiers
|
.followed_dossiers
|
||||||
.where(groupe_instructeur: current_instructeur.groupe_instructeurs)
|
.where(groupe_instructeur_id: groupe_instructeur_ids)
|
||||||
.for_procedure(procedure)
|
|
||||||
.en_cours
|
.en_cours
|
||||||
|
|
||||||
@followed_dossiers_id = current_instructeur
|
@followed_dossiers_id = @followed_dossiers.pluck(:id)
|
||||||
.followed_dossiers
|
|
||||||
.where(groupe_instructeur: current_instructeur.groupe_instructeurs)
|
|
||||||
.for_procedure(procedure)
|
|
||||||
.pluck(:id)
|
|
||||||
|
|
||||||
@termines_dossiers = current_instructeur
|
@termines_dossiers = dossiers_visibles.termine
|
||||||
.dossiers
|
@all_state_dossiers = dossiers_visibles.all_state
|
||||||
.for_procedure(procedure)
|
@archived_dossiers = dossiers_visibles.archived
|
||||||
.termine
|
|
||||||
|
|
||||||
@all_state_dossiers = current_instructeur
|
|
||||||
.dossiers
|
|
||||||
.for_procedure(procedure)
|
|
||||||
.all_state
|
|
||||||
|
|
||||||
@archived_dossiers = current_instructeur
|
|
||||||
.dossiers
|
|
||||||
.for_procedure(procedure)
|
|
||||||
.archived
|
|
||||||
|
|
||||||
@dossiers = case statut
|
@dossiers = case statut
|
||||||
when 'a-suivre'
|
when 'a-suivre'
|
||||||
|
@ -241,12 +230,28 @@ module Instructeurs
|
||||||
current_instructeur.assign_to.joins(:groupe_instructeur).find_by(groupe_instructeurs: { procedure: procedure })
|
current_instructeur.assign_to.joins(:groupe_instructeur).find_by(groupe_instructeurs: { procedure: procedure })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def assign_tos
|
||||||
|
@assign_tos ||= current_instructeur
|
||||||
|
.assign_to
|
||||||
|
.joins(:groupe_instructeur)
|
||||||
|
.where(groupe_instructeur: { procedure_id: procedure_id })
|
||||||
|
end
|
||||||
|
|
||||||
|
def groupe_instructeur_ids
|
||||||
|
@groupe_instructeur_ids ||= assign_tos
|
||||||
|
.map(&:groupe_instructeur_id)
|
||||||
|
end
|
||||||
|
|
||||||
def statut
|
def statut
|
||||||
@statut ||= (params[:statut].presence || 'a-suivre')
|
@statut ||= (params[:statut].presence || 'a-suivre')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def procedure_id
|
||||||
|
params[:procedure_id]
|
||||||
|
end
|
||||||
|
|
||||||
def procedure
|
def procedure
|
||||||
Procedure.find(params[:procedure_id])
|
Procedure.find(procedure_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_ownership!
|
def ensure_ownership!
|
||||||
|
@ -267,7 +272,7 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_procedure_presentation
|
def get_procedure_presentation
|
||||||
procedure_presentation, errors = current_instructeur.procedure_presentation_and_errors_for_procedure_id(params[:procedure_id])
|
procedure_presentation, errors = current_instructeur.procedure_presentation_and_errors_for_procedure_id(procedure_id)
|
||||||
if errors.present?
|
if errors.present?
|
||||||
flash[:alert] = "Votre affichage a dû être réinitialisé en raison du problème suivant : " + errors.full_messages.join(', ')
|
flash[:alert] = "Votre affichage a dû être réinitialisé en raison du problème suivant : " + errors.full_messages.join(', ')
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,23 +50,27 @@ module Manager
|
||||||
def emails
|
def emails
|
||||||
@user = User.find(params[:id])
|
@user = User.find(params[:id])
|
||||||
|
|
||||||
transactionnal_api = ::SibApiV3Sdk::TransactionalEmailsApi.new
|
email_services = [
|
||||||
|
Mailjet::API.new,
|
||||||
|
Sendinblue::API.new
|
||||||
|
]
|
||||||
|
|
||||||
@transactionnal_emails = transactionnal_api.get_transac_emails_list(email: @user.email)
|
@sent_mails = email_services
|
||||||
@events = transactionnal_api.get_email_event_report(email: @user.email, days: 30)
|
.filter(&:properly_configured?)
|
||||||
|
.map { |api| api.sent_mails(@user.email) }
|
||||||
rescue ::SibApiV3Sdk::ApiError => e
|
.flatten
|
||||||
flash.alert = "Impossible de récupérer les emails de cet utilisateur chez Sendinblue : #{e.message}"
|
.sort_by(&:delivered_at)
|
||||||
|
.reverse
|
||||||
end
|
end
|
||||||
|
|
||||||
def unblock_user
|
def unblock_email
|
||||||
@user = User.find(params[:id])
|
@user = User.find(params[:user_id])
|
||||||
|
if Sendinblue::API.new.unblock_user(@user.email)
|
||||||
transactionnal_api = ::SibApiV3Sdk::TransactionalEmailsApi.new
|
flash.notice = "L'adresse email a été débloquée auprès de Sendinblue"
|
||||||
transactionnal_api.smtp_blocked_contacts_email_delete(@user.email)
|
else
|
||||||
|
flash.alert = "Impossible de débloquer cette addresse email auprès de Sendinblue"
|
||||||
rescue ::SibApiV3Sdk::ApiError => e
|
end
|
||||||
flash.alert = "Impossible de débloquer cet email auprès de Sendinblue : #{e.message}"
|
redirect_to emails_manager_user_path(@user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
module EmailHelper
|
module EmailHelper
|
||||||
def event_color_code(email_events)
|
def status_color_code(status)
|
||||||
unique_events = email_events.map(&:event)
|
if status.include?('delivered')
|
||||||
if unique_events.include?('delivered')
|
|
||||||
return 'email-sent'
|
return 'email-sent'
|
||||||
elsif unique_events.include?('blocked') || unique_events.include?('hardBounces')
|
elsif status.include?('blocked') || status.include?('hardBounces')
|
||||||
return 'email-blocked'
|
return 'email-blocked'
|
||||||
else
|
else
|
||||||
return ''
|
return ''
|
||||||
|
|
37
app/lib/mailjet/api.rb
Normal file
37
app/lib/mailjet/api.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
class Mailjet::API
|
||||||
|
def properly_configured?
|
||||||
|
[Mailjet.config.api_key, Mailjet.config.secret_key].all?(&:present?)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get messages sent to a user through SendInBlue.
|
||||||
|
#
|
||||||
|
# Returns an array of SentMail objects.
|
||||||
|
def sent_mails(email_address)
|
||||||
|
contact = Mailjet::Contact.find(email_address)
|
||||||
|
if contact.nil?
|
||||||
|
Rails.logger.info "Mailjet::API: no contact found for email address '#{email_address}'"
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
messages = Mailjet::Message.all(
|
||||||
|
contact: contact.attributes['id'],
|
||||||
|
from_ts: 30.days.ago.to_datetime.rfc3339,
|
||||||
|
show_subject: true
|
||||||
|
)
|
||||||
|
|
||||||
|
messages.map do |message|
|
||||||
|
SentMail.new(
|
||||||
|
from: nil,
|
||||||
|
to: email_address,
|
||||||
|
subject: message.attributes['subject'],
|
||||||
|
delivered_at: message.attributes['arrived_at'],
|
||||||
|
status: message.attributes['status'],
|
||||||
|
service_name: 'Mailjet',
|
||||||
|
external_url: 'https://app.mailjet.com/contacts/subscribers/contact_list'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
rescue Mailjet::ApiError => e
|
||||||
|
Rails.logger.error e.message
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,6 +16,7 @@ class Sendinblue::API
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_contact(email, attributes = {})
|
def update_contact(email, attributes = {})
|
||||||
|
# TODO: refactor this to use the official SiB SDK (by using contact create + attributes)
|
||||||
req = post_api_request('contacts', email: email, attributes: attributes, updateEnabled: true)
|
req = post_api_request('contacts', email: email, attributes: attributes, updateEnabled: true)
|
||||||
req.on_complete do |response|
|
req.on_complete do |response|
|
||||||
if !response.success?
|
if !response.success?
|
||||||
|
@ -25,6 +26,44 @@ class Sendinblue::API
|
||||||
hydra.queue(req)
|
hydra.queue(req)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Get messages sent to a user through SendInBlue.
|
||||||
|
#
|
||||||
|
# Returns an array of SentMail objects.
|
||||||
|
def sent_mails(email_address)
|
||||||
|
client = ::SibApiV3Sdk::TransactionalEmailsApi.new
|
||||||
|
@events = client.get_email_event_report(email: email_address, days: 30).events
|
||||||
|
|
||||||
|
if @events.blank?
|
||||||
|
Rails.logger.info "SendInBlue::API: no messages found for email address '#{email_address}'"
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
@events.group_by(&:message_id).values.map do |message_events|
|
||||||
|
latest_event = message_events.first
|
||||||
|
SentMail.new(
|
||||||
|
from: latest_event.from,
|
||||||
|
to: latest_event.email,
|
||||||
|
subject: latest_event.subject,
|
||||||
|
delivered_at: parse_date(latest_event.date),
|
||||||
|
status: latest_event.event,
|
||||||
|
service_name: 'SendInBlue',
|
||||||
|
external_url: 'https://app-smtp.sendinblue.com/log'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
rescue ::SibApiV3Sdk::ApiError => e
|
||||||
|
Rails.logger.error e.message
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
def unblock_user(email_address)
|
||||||
|
client = ::SibApiV3Sdk::TransactionalEmailsApi.new
|
||||||
|
client.smtp_blocked_contacts_email_delete(email_address)
|
||||||
|
true
|
||||||
|
rescue ::SibApiV3Sdk::ApiError => e
|
||||||
|
Rails.logger.error e.message
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
hydra.run
|
hydra.run
|
||||||
@hydra = nil
|
@hydra = nil
|
||||||
|
@ -70,4 +109,8 @@ class Sendinblue::API
|
||||||
def client_key
|
def client_key
|
||||||
Rails.application.secrets.sendinblue[:api_v3_key]
|
Rails.application.secrets.sendinblue[:api_v3_key]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def parse_date(date)
|
||||||
|
date.is_a?(String) ? Time.zone.parse(date) : date
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
3
app/lib/sent_mail.rb
Normal file
3
app/lib/sent_mail.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Represent an email sent using an external API
|
||||||
|
class SentMail < Struct.new(:from, :to, :subject, :delivered_at, :status, :service_name, :external_url, keyword_init: true)
|
||||||
|
end
|
|
@ -5,10 +5,12 @@ class AvisMailer < ApplicationMailer
|
||||||
layout 'mailers/layout'
|
layout 'mailers/layout'
|
||||||
|
|
||||||
def avis_invitation(avis)
|
def avis_invitation(avis)
|
||||||
|
if avis.dossier.present?
|
||||||
@avis = avis
|
@avis = avis
|
||||||
email = @avis.expert&.email
|
email = @avis.expert&.email
|
||||||
subject = "Donnez votre avis sur le dossier nº #{@avis.dossier.id} (#{@avis.dossier.procedure.libelle})"
|
subject = "Donnez votre avis sur le dossier nº #{@avis.dossier.id} (#{@avis.dossier.procedure.libelle})"
|
||||||
|
|
||||||
mail(to: email, subject: subject)
|
mail(to: email, subject: subject)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -312,7 +312,6 @@ class Dossier < ApplicationRecord
|
||||||
.where.not(user: users_who_submitted)
|
.where.not(user: users_who_submitted)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
|
|
||||||
scope :for_api_v2, -> { includes(procedure: [:administrateurs, :attestation_template], etablissement: [], individual: [], traitements: []) }
|
scope :for_api_v2, -> { includes(procedure: [:administrateurs, :attestation_template], etablissement: [], individual: [], traitements: []) }
|
||||||
|
|
||||||
scope :with_notifications, -> do
|
scope :with_notifications, -> do
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
# birthdate :date
|
# birthdate :date
|
||||||
# birthplace :string
|
# birthplace :string
|
||||||
|
# data :jsonb
|
||||||
# email_france_connect :string
|
# email_france_connect :string
|
||||||
# family_name :string
|
# family_name :string
|
||||||
# gender :string
|
# gender :string
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# Table name: instructeurs
|
# Table name: instructeurs
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
|
# bypass_email_login_token :boolean default(FALSE), not null
|
||||||
# encrypted_login_token :text
|
# encrypted_login_token :text
|
||||||
# login_token_created_at :datetime
|
# login_token_created_at :datetime
|
||||||
# created_at :datetime
|
# created_at :datetime
|
||||||
|
@ -212,6 +213,32 @@ class Instructeur < ApplicationRecord
|
||||||
"Instructeur:#{id}"
|
"Instructeur:#{id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def dossiers_count_summary(groupe_instructeur_ids)
|
||||||
|
query = <<~EOF
|
||||||
|
SELECT
|
||||||
|
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.id IS NULL) AS a_suivre,
|
||||||
|
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('en_construction', 'en_instruction') AND follows.instructeur_id = :instructeur_id) AS suivis,
|
||||||
|
COUNT(DISTINCT dossiers.id) FILTER (where not archived AND dossiers.state in ('accepte', 'refuse', 'sans_suite')) AS traites,
|
||||||
|
COUNT(DISTINCT dossiers.id) FILTER (where not archived) AS tous,
|
||||||
|
COUNT(DISTINCT dossiers.id) FILTER (where archived) AS archives
|
||||||
|
FROM "dossiers"
|
||||||
|
LEFT OUTER JOIN follows
|
||||||
|
ON follows.dossier_id = dossiers.id
|
||||||
|
AND follows.unfollowed_at IS NULL
|
||||||
|
WHERE "dossiers"."hidden_at" IS NULL
|
||||||
|
AND "dossiers"."state" != 'brouillon'
|
||||||
|
AND "dossiers"."groupe_instructeur_id" in (:groupe_instructeur_ids)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sanitized_query = ActiveRecord::Base.sanitize_sql([
|
||||||
|
query,
|
||||||
|
instructeur_id: id,
|
||||||
|
groupe_instructeur_ids: groupe_instructeur_ids
|
||||||
|
])
|
||||||
|
|
||||||
|
Dossier.connection.select_all(sanitized_query).first
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
||||||
|
|
|
@ -632,47 +632,6 @@ class Procedure < ApplicationRecord
|
||||||
draft_revision.deep_clone(include: [:revision_types_de_champ, :revision_types_de_champ_private])
|
draft_revision.deep_clone(include: [:revision_types_de_champ, :revision_types_de_champ_private])
|
||||||
end
|
end
|
||||||
|
|
||||||
def dossiers_count_for_instructeur(instructeur)
|
|
||||||
query = <<-EOF
|
|
||||||
SELECT
|
|
||||||
COUNT(*) FILTER ( WHERE "dossiers"."state" in ('en_construction', 'en_instruction') and "follows"."id" IS NULL and not "dossiers"."archived") AS a_suivre,
|
|
||||||
COUNT(*) FILTER ( WHERE "dossiers"."state" in ('en_construction', 'en_instruction') and "follows"."instructeur_id" = :instructeur_id and not "dossiers"."archived" and "follows"."unfollowed_at" IS NULL) AS suivis,
|
|
||||||
COUNT(*) FILTER ( WHERE "dossiers"."state" in ('accepte', 'refuse', 'sans_suite') and not "dossiers"."archived" ) AS termines,
|
|
||||||
COUNT(*) FILTER ( WHERE "dossiers"."state" != 'brouillon' and not "dossiers"."archived" ) AS total,
|
|
||||||
COUNT(*) FILTER ( WHERE "dossiers"."archived" ) AS archived
|
|
||||||
FROM
|
|
||||||
"dossiers"
|
|
||||||
INNER JOIN
|
|
||||||
"groupe_instructeurs"
|
|
||||||
ON "dossiers"."groupe_instructeur_id" = "groupe_instructeurs"."id"
|
|
||||||
INNER JOIN
|
|
||||||
"assign_tos"
|
|
||||||
ON "groupe_instructeurs"."id" = "assign_tos"."groupe_instructeur_id"
|
|
||||||
INNER JOIN
|
|
||||||
"procedures"
|
|
||||||
ON "groupe_instructeurs"."procedure_id" = "procedures"."id"
|
|
||||||
LEFT OUTER JOIN
|
|
||||||
"follows"
|
|
||||||
ON "follows"."dossier_id" = "dossiers"."id"
|
|
||||||
AND "follows"."unfollowed_at" IS NULL
|
|
||||||
WHERE
|
|
||||||
"dossiers"."hidden_at" IS NULL
|
|
||||||
AND "assign_tos"."instructeur_id" = :instructeur_id
|
|
||||||
AND "procedures"."id" = :procedure_id
|
|
||||||
GROUP BY
|
|
||||||
groupe_instructeurs.procedure_id, procedures.libelle
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sanitized_query = ActiveRecord::Base.sanitize_sql([
|
|
||||||
query,
|
|
||||||
instructeur_id: instructeur.id,
|
|
||||||
procedure_id: self.id,
|
|
||||||
now: Time.zone.now
|
|
||||||
])
|
|
||||||
|
|
||||||
Procedure.connection.select_all(sanitized_query).first || { "a_suivre" => 0, "suivis" => 0, "termines" => 0, "total" => 0, "archived" => 0 }
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def before_publish
|
def before_publish
|
||||||
|
|
|
@ -24,29 +24,29 @@
|
||||||
= tab_item('à suivre',
|
= tab_item('à suivre',
|
||||||
instructeur_procedure_path(@procedure, statut: 'a-suivre'),
|
instructeur_procedure_path(@procedure, statut: 'a-suivre'),
|
||||||
active: @statut == 'a-suivre',
|
active: @statut == 'a-suivre',
|
||||||
badge: number_with_html_delimiter(@a_suivre_dossiers.count))
|
badge: number_with_html_delimiter(@a_suivre_count))
|
||||||
|
|
||||||
= tab_item(t('pluralize.followed', count: @followed_dossiers.count),
|
= tab_item(t('pluralize.followed', count: @suivis_count),
|
||||||
instructeur_procedure_path(@procedure, statut: 'suivis'),
|
instructeur_procedure_path(@procedure, statut: 'suivis'),
|
||||||
active: @statut == 'suivis',
|
active: @statut == 'suivis',
|
||||||
badge: number_with_html_delimiter(@followed_dossiers.count),
|
badge: number_with_html_delimiter(@suivis_count),
|
||||||
notification: @has_en_cours_notifications)
|
notification: @has_en_cours_notifications)
|
||||||
|
|
||||||
= tab_item(t('pluralize.processed', count: @termines_dossiers.count),
|
= tab_item(t('pluralize.processed', count: @traites_count),
|
||||||
instructeur_procedure_path(@procedure, statut: 'traites'),
|
instructeur_procedure_path(@procedure, statut: 'traites'),
|
||||||
active: @statut == 'traites',
|
active: @statut == 'traites',
|
||||||
badge: number_with_html_delimiter(@termines_dossiers.count),
|
badge: number_with_html_delimiter(@traites_count),
|
||||||
notification: @has_termine_notifications)
|
notification: @has_termine_notifications)
|
||||||
|
|
||||||
= tab_item('tous les dossiers',
|
= tab_item('tous les dossiers',
|
||||||
instructeur_procedure_path(@procedure, statut: 'tous'),
|
instructeur_procedure_path(@procedure, statut: 'tous'),
|
||||||
active: @statut == 'tous',
|
active: @statut == 'tous',
|
||||||
badge: number_with_html_delimiter(@all_state_dossiers.count))
|
badge: number_with_html_delimiter(@tous_count))
|
||||||
|
|
||||||
= tab_item(t('pluralize.archived', count: @archived_dossiers.count),
|
= tab_item(t('pluralize.archived', count: @archives_count),
|
||||||
instructeur_procedure_path(@procedure, statut: 'archives'),
|
instructeur_procedure_path(@procedure, statut: 'archives'),
|
||||||
active: @statut == 'archives',
|
active: @statut == 'archives',
|
||||||
badge: number_with_html_delimiter(@archived_dossiers.count))
|
badge: number_with_html_delimiter(@archives_count))
|
||||||
|
|
||||||
.procedure-actions
|
.procedure-actions
|
||||||
= render partial: "download_dossiers",
|
= render partial: "download_dossiers",
|
||||||
|
|
|
@ -17,10 +17,14 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="main-content__body">
|
<section class="main-content__body">
|
||||||
<h2>Historique des email</h2>
|
<h2 style="font-size: 1.3em; margin: 24px 0 8px 0">Historique des email</h2>
|
||||||
<% if @transactionnal_emails.present? %>
|
<% if @sent_mails.present? %>
|
||||||
<p>
|
<p>
|
||||||
Cet historique contient les 30 derniers jours. Pour un recherche plus fine, il faut <a href="https://app-smtp.sendinblue.com/log">fouiller les logs</a>.
|
Cet historique contient les 30 derniers jours.
|
||||||
|
Pour un recherche plus fine, il faut fouiller les
|
||||||
|
<a href="https://app-smtp.sendinblue.com/log">logs de SendInblue</a>
|
||||||
|
ou
|
||||||
|
<a href="https://app.mailjet.com/contacts/subscribers/contact_list">de Mailjet</a>.
|
||||||
</p>
|
</p>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -29,17 +33,22 @@
|
||||||
Émetteur
|
Émetteur
|
||||||
</th>
|
</th>
|
||||||
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
||||||
Sujet
|
Objet
|
||||||
</th>
|
</th>
|
||||||
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
||||||
Date
|
Date
|
||||||
</th>
|
</th>
|
||||||
|
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
||||||
|
Statut
|
||||||
|
</th>
|
||||||
|
<th class="cell-label cell-label--string cell-label--false" scope="col" role="columnheader" aria-sort="none">
|
||||||
|
Prestataire
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @transactionnal_emails&.transactional_emails&.reverse&.each do |email| %>
|
<% @sent_mails.each do |email| %>
|
||||||
<% matching_events = @events&.events&.select { |e| e.message_id == email.message_id } %>
|
<tr class="<%= status_color_code(email.status) %>">
|
||||||
<tr class="<%= event_color_code(matching_events) %>">
|
|
||||||
<td class="cell-data cell-data--string" style="">
|
<td class="cell-data cell-data--string" style="">
|
||||||
<%= email.from %>
|
<%= email.from %>
|
||||||
</td>
|
</td>
|
||||||
|
@ -47,26 +56,28 @@
|
||||||
<%= email.subject %>
|
<%= email.subject %>
|
||||||
</td>
|
</td>
|
||||||
<td class="cell-data cell-data--string" style="text-align: center;">
|
<td class="cell-data cell-data--string" style="text-align: center;">
|
||||||
<%= l(email.date.is_a?(String) ? Time.zone.parse(email.date) : email.date, format: '%d/%m/%y à %H:%M') %>
|
<%= l(email.delivered_at, format: :long) %>
|
||||||
</td>
|
</td>
|
||||||
<td class="cell-data cell-data--string" style="text-align: center;">
|
<td class="cell-data cell-data--string" style="text-align: center;">
|
||||||
<ul>
|
<%= email.status %>
|
||||||
|
</td>
|
||||||
<% matching_events.each do |event|%>
|
<td class="cell-data cell-data--string" style="">
|
||||||
<li><%= event.event %></li>
|
<%= link_to email.service_name, email.external_url, style: 'text-decoration: underline' %>
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>Historique indisponible. Cet email n'existe pas chez Sendinblue, ou nous n'avons pas réussi à échanger.
|
<p>Historique indisponible. Cette adresse email n'existe pas chez nos prestataires d'envoi, ou nous n'avons pas réussi à en charger des données.
|
||||||
Vous pouvez éventuellement <a href="https://app-smtp.sendinblue.com/log">fouiller leurs logs</a>.</p>
|
Vous pouvez éventuellement fouiller les
|
||||||
|
<a href="https://app-smtp.sendinblue.com/log">logs de SendInBlue</a>
|
||||||
|
ou
|
||||||
|
<a href="https://app.mailjet.com/contacts/subscribers/contact_list">de Mailjet</a>.
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<h2>Problèmes potentiel</h2>
|
<h2 style="font-size: 1.3em; margin: 24px 0 8px 0">Problèmes potentiel</h2>
|
||||||
|
|
||||||
<% if @user.confirmed? %>
|
<% if @user.confirmed? %>
|
||||||
<p><strong>Compte activé, n'arrive pas à se connecter</strong> ? <button class="btn btn-secondary btn-small" onclick="reveal_email('#activated-cant-connect')">Voir la suggestion d’email</button></p>
|
<p><strong>Compte activé, n'arrive pas à se connecter</strong> ? <button class="btn btn-secondary btn-small" onclick="reveal_email('#activated-cant-connect')">Voir la suggestion d’email</button></p>
|
||||||
|
@ -95,7 +106,11 @@ https://www.demarches-simplifiees.fr/users/password/new
|
||||||
|
|
||||||
Cordialement</pre>
|
Cordialement</pre>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p><strong>Compte <a href="https://app-smtp.sendinblue.com/block">bloqué</a> chez Sendinblue ?</strong> Vous pouvez le <%= link_to('débloquer', manager_user_unblock_email_path(@user), method: :put, class: 'button', remote: true) %> puis lui envoyer <button class="btn btn-secondary btn-small" onclick="reveal_email('#unblock_email')">le mail suivant</button></p>
|
<p>
|
||||||
|
<strong>Compte <a href="https://app-smtp.sendinblue.com/block">bloqué</a> chez Sendinblue ?</strong>
|
||||||
|
Vous pouvez le <%= link_to('débloquer', manager_user_unblock_email_path(@user), method: :put, class: 'button') %>
|
||||||
|
puis lui envoyer <button class="btn btn-secondary btn-small" onclick="reveal_email('#unblock_email')">le mail suivant</button>
|
||||||
|
</p>
|
||||||
<pre class="hidden" id="unblock_email">
|
<pre class="hidden" id="unblock_email">
|
||||||
Bonjour,
|
Bonjour,
|
||||||
|
|
||||||
|
@ -106,12 +121,18 @@ Cela peut arriver si vous, ou ceux qui gèrent vos emails, marquent nos emails c
|
||||||
|
|
||||||
Nous vous invitons donc à autoriser les emails émis depuis demarches-simplifiees.fr
|
Nous vous invitons donc à autoriser les emails émis depuis demarches-simplifiees.fr
|
||||||
|
|
||||||
Bien cordialement</pre>
|
Bien cordialement
|
||||||
<p><strong>Problème chez Sendinblue ?</strong> Regardez leur <a href="https://status.sendinblue.com/">page de status</a>. <button class="btn btn-secondary btn-small" onclick="reveal_email('#pb-sendinblue')">Voir la suggestion d’email</button></p>
|
</pre>
|
||||||
|
<p>
|
||||||
|
<strong>Problème chez Sendinblue ?</strong>
|
||||||
|
Regardez leur <a href="https://status.sendinblue.com/">page de status</a>.
|
||||||
|
<button class="btn btn-secondary btn-small" onclick="reveal_email('#pb-sendinblue')">Voir la suggestion d’email</button>
|
||||||
|
</p>
|
||||||
<pre class="hidden" id="pb-sendinblue">
|
<pre class="hidden" id="pb-sendinblue">
|
||||||
Bonjour,
|
Bonjour,
|
||||||
Désolé, notre prestataire d'envoi d'email subit actuellement des soucis avec sa plateforme ;
|
Désolé, notre prestataire d'envoi d'email subit actuellement des soucis avec sa plateforme ;
|
||||||
vous allez recevoir cet email sous peu.
|
vous allez recevoir cet email sous peu.
|
||||||
|
|
||||||
Bien cordialement,</pre>
|
Bien cordialement,
|
||||||
|
</pre>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
class AddBypassEmailLoginTokenColumnToInstructeur < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
# This may take a while if running on Postgres < 11
|
||||||
|
add_column :instructeurs, :bypass_email_login_token, :boolean, default: false, null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddDataColumnToFranceConnectInformations < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :france_connect_informations, :data, :jsonb
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2021_04_09_075105) do
|
ActiveRecord::Schema.define(version: 2021_04_12_092710) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -410,6 +410,7 @@ ActiveRecord::Schema.define(version: 2021_04_09_075105) do
|
||||||
t.string "email_france_connect"
|
t.string "email_france_connect"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
|
t.jsonb "data"
|
||||||
t.index ["user_id"], name: "index_france_connect_informations_on_user_id"
|
t.index ["user_id"], name: "index_france_connect_informations_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -459,6 +460,7 @@ ActiveRecord::Schema.define(version: 2021_04_09_075105) do
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.text "encrypted_login_token"
|
t.text "encrypted_login_token"
|
||||||
t.datetime "login_token_created_at"
|
t.datetime "login_token_created_at"
|
||||||
|
t.boolean "bypass_email_login_token", default: false, null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "invites", id: :serial, force: :cascade do |t|
|
create_table "invites", id: :serial, force: :cascade do |t|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: populate_bypass_email_login'
|
||||||
|
task populate_bypass_email_login: :environment do
|
||||||
|
user_ids = Flipper::Adapters::ActiveRecord::Gate
|
||||||
|
.where(feature_key: 'instructeur_bypass_email_login_token')
|
||||||
|
.pluck(:value)
|
||||||
|
.filter { |s| s.start_with?('User:') }
|
||||||
|
.map { |s| s.gsub('User:', '') }
|
||||||
|
.map(&:to_i)
|
||||||
|
|
||||||
|
Instructeur
|
||||||
|
.where(user: { id: user_ids })
|
||||||
|
.update_all(bypass_email_login_token: true)
|
||||||
|
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,39 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: fill_missing_date_of_fc'
|
||||||
|
task fill_missing_date_of_fc: :environment do
|
||||||
|
rake_puts "Remove invalid FranceConnectInformation records with no associated user…"
|
||||||
|
FranceConnectInformation
|
||||||
|
.where(user_id: nil)
|
||||||
|
.destroy_all
|
||||||
|
|
||||||
|
rake_puts "Fill-in missing created_at from updated_at column on FranceConnectInformation records…"
|
||||||
|
created_from_updated_sql = <<~EOF
|
||||||
|
created_at = updated_at,
|
||||||
|
data = '{ "note": "missing created_at has been copied from updated_at" }'
|
||||||
|
EOF
|
||||||
|
|
||||||
|
FranceConnectInformation
|
||||||
|
.where(created_at: nil)
|
||||||
|
.where.not(updated_at: nil)
|
||||||
|
.update_all(created_from_updated_sql)
|
||||||
|
|
||||||
|
rake_puts "Fill-in missing created_at, updated_at columns from users.created on FranceConnectInformation records…"
|
||||||
|
created_updated_from_user_created_sql = <<~EOF
|
||||||
|
UPDATE france_connect_informations
|
||||||
|
SET created_at = users.created_at,
|
||||||
|
updated_at = users.created_at,
|
||||||
|
data = '{ "note": "missing created_at, updated_at have been copied from users.created_at" }'
|
||||||
|
FROM users
|
||||||
|
WHERE users.id = france_connect_informations.user_id
|
||||||
|
AND france_connect_informations.created_at IS NULL
|
||||||
|
AND france_connect_informations.updated_at IS NULL
|
||||||
|
EOF
|
||||||
|
|
||||||
|
FranceConnectInformation
|
||||||
|
.connection
|
||||||
|
.execute(created_updated_from_user_created_sql)
|
||||||
|
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
describe '20210412093054_fill_missing_date_of_fc' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:fill_missing_date_of_fc'] }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, created_at: Time.zone.parse('2000/01/01')) }
|
||||||
|
|
||||||
|
let!(:valid_fci) do
|
||||||
|
FranceConnectInformation.create!(
|
||||||
|
user: user,
|
||||||
|
france_connect_particulier_id: '123',
|
||||||
|
created_at: Time.zone.parse('2010/01/01'),
|
||||||
|
updated_at: Time.zone.parse('2012/01/01')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:missing_created_fci) do
|
||||||
|
fci = FranceConnectInformation.create!(
|
||||||
|
user: user,
|
||||||
|
france_connect_particulier_id: '123',
|
||||||
|
updated_at: Time.zone.parse('2013/01/01')
|
||||||
|
)
|
||||||
|
|
||||||
|
fci.update_column('created_at', nil)
|
||||||
|
fci
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:missing_created_updated_fci) do
|
||||||
|
fci = FranceConnectInformation.create!(
|
||||||
|
user: user,
|
||||||
|
france_connect_particulier_id: '123'
|
||||||
|
)
|
||||||
|
|
||||||
|
fci.update_column('created_at', nil)
|
||||||
|
fci.update_column('updated_at', nil)
|
||||||
|
fci
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:missing_created_updated_without_user_fci) do
|
||||||
|
fci = FranceConnectInformation.create!(
|
||||||
|
france_connect_particulier_id: '123'
|
||||||
|
)
|
||||||
|
|
||||||
|
fci.update_column('created_at', nil)
|
||||||
|
fci.update_column('updated_at', nil)
|
||||||
|
fci
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
rake_task.invoke
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
it "does not change valid fci" do
|
||||||
|
valid_fci.reload
|
||||||
|
expect(valid_fci.created_at).to eq(Time.zone.parse('2010/01/01'))
|
||||||
|
expect(valid_fci.updated_at).to eq(Time.zone.parse('2012/01/01'))
|
||||||
|
expect(valid_fci.data).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fills missing created from updated" do
|
||||||
|
missing_created_fci.reload
|
||||||
|
expect(missing_created_fci.created_at).to eq(Time.zone.parse('2013/01/01'))
|
||||||
|
expect(missing_created_fci.data['note']).to eq("missing created_at has been copied from updated_at")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fills missing created, updated from users created" do
|
||||||
|
missing_created_updated_fci.reload
|
||||||
|
expect(missing_created_updated_fci.created_at).to eq(Time.zone.parse('2000/01/01'))
|
||||||
|
expect(missing_created_updated_fci.updated_at).to eq(Time.zone.parse('2000/01/01'))
|
||||||
|
expect(missing_created_updated_fci.data['note']).to eq("missing created_at, updated_at have been copied from users.created_at")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "destroys fci when there is no user" do
|
||||||
|
expect { missing_created_updated_without_user_fci.reload }
|
||||||
|
.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,7 +6,7 @@ RSpec.describe AvisMailer, type: :mailer do
|
||||||
let(:experts_procedure) { create(:experts_procedure, expert: expert, procedure: dossier.procedure) }
|
let(:experts_procedure) { create(:experts_procedure, expert: expert, procedure: dossier.procedure) }
|
||||||
let(:avis) { create(:avis, dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, introduction: 'intro') }
|
let(:avis) { create(:avis, dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, introduction: 'intro') }
|
||||||
|
|
||||||
subject { described_class.avis_invitation(avis) }
|
subject { described_class.avis_invitation(avis.reload) }
|
||||||
|
|
||||||
it { expect(subject.subject).to eq("Donnez votre avis sur le dossier nº #{avis.dossier.id} (#{avis.dossier.procedure.libelle})") }
|
it { expect(subject.subject).to eq("Donnez votre avis sur le dossier nº #{avis.dossier.id} (#{avis.dossier.procedure.libelle})") }
|
||||||
it { expect(subject.body).to have_text("Vous avez été invité par\r\n#{avis.claimant.email}\r\nà donner votre avis sur le dossier nº #{avis.dossier.id} de la démarche :\r\n#{avis.dossier.procedure.libelle}") }
|
it { expect(subject.body).to have_text("Vous avez été invité par\r\n#{avis.claimant.email}\r\nà donner votre avis sur le dossier nº #{avis.dossier.id} de la démarche :\r\n#{avis.dossier.procedure.libelle}") }
|
||||||
|
@ -16,5 +16,13 @@ RSpec.describe AvisMailer, type: :mailer do
|
||||||
context 'when the recipient is not already registered' do
|
context 'when the recipient is not already registered' do
|
||||||
it { expect(subject.body).to include(sign_up_expert_avis_url(avis.dossier.procedure.id, avis.id, avis.expert.email)) }
|
it { expect(subject.body).to include(sign_up_expert_avis_url(avis.dossier.procedure.id, avis.id, avis.expert.email)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the dossier has been deleted before the avis was sent' do
|
||||||
|
before { dossier.update(hidden_at: Time.zone.now) }
|
||||||
|
|
||||||
|
it 'doesn’t send the email' do
|
||||||
|
expect(subject.body).to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1154,23 +1154,6 @@ describe Dossier do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#for_procedure' do
|
|
||||||
let!(:procedure_1) { create(:procedure) }
|
|
||||||
let!(:procedure_2) { create(:procedure) }
|
|
||||||
|
|
||||||
let!(:dossier_1_1) { create(:dossier, procedure: procedure_1) }
|
|
||||||
let!(:dossier_1_2) { create(:dossier, procedure: procedure_1) }
|
|
||||||
let!(:dossier_2_1) { create(:dossier, procedure: procedure_2) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
gi_1_2 = procedure_1.groupe_instructeurs.create(label: 2)
|
|
||||||
gi_1_2.dossiers << dossier_1_2
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(Dossier.for_procedure(procedure_1)).to contain_exactly(dossier_1_1, dossier_1_2) }
|
|
||||||
it { expect(Dossier.for_procedure(procedure_2)).to contain_exactly(dossier_2_1) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#notify_draft_not_submitted' do
|
describe '#notify_draft_not_submitted' do
|
||||||
let!(:user1) { create(:user) }
|
let!(:user1) { create(:user) }
|
||||||
let!(:user2) { create(:user) }
|
let!(:user2) { create(:user) }
|
||||||
|
|
|
@ -568,6 +568,152 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#dossiers_count_summary" do
|
||||||
|
let(:instructeur_2) { create(:instructeur) }
|
||||||
|
let(:instructeur_3) { create(:instructeur) }
|
||||||
|
let(:procedure) { create(:procedure, instructeurs: [instructeur_2, instructeur_3]) }
|
||||||
|
let(:gi_1) { procedure.groupe_instructeurs.first }
|
||||||
|
let(:gi_2) { procedure.groupe_instructeurs.create(label: '2') }
|
||||||
|
let(:gi_3) { procedure.groupe_instructeurs.create(label: '3') }
|
||||||
|
|
||||||
|
subject do
|
||||||
|
instructeur_2.dossiers_count_summary([gi_1.id, gi_2.id])
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when logged in, and belonging to gi_1, gi_2" do
|
||||||
|
before do
|
||||||
|
instructeur.groupe_instructeurs << gi_2
|
||||||
|
end
|
||||||
|
|
||||||
|
context "without any dossier" do
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(0) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a new brouillon dossier' do
|
||||||
|
let!(:brouillon_dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(0) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a new dossier without follower' do
|
||||||
|
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(1) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(1) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
|
||||||
|
context 'and dossiers without follower on each of the others groups' do
|
||||||
|
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
|
||||||
|
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
|
||||||
|
|
||||||
|
before { subject }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(2) }
|
||||||
|
it { expect(subject['tous']).to eq(2) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a new dossier with a follower' do
|
||||||
|
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
instructeur_2.followed_dossiers << new_followed_dossier
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(1) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(1) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
|
||||||
|
context 'and another one follows the same dossier' do
|
||||||
|
before do
|
||||||
|
instructeur_3.followed_dossiers << new_followed_dossier
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(1) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(1) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and dossier with a follower on each of the others groups' do
|
||||||
|
let!(:new_follow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
|
||||||
|
let!(:new_follow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
instructeur_2.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3
|
||||||
|
end
|
||||||
|
|
||||||
|
# followed dossiers on another groupe should not be displayed
|
||||||
|
it { expect(subject['suivis']).to eq(2) }
|
||||||
|
it { expect(subject['tous']).to eq(2) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and dossier with a follower is unfollowed' do
|
||||||
|
before do
|
||||||
|
instructeur_2.unfollow(new_followed_dossier)
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(1) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(1) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a termine dossier' do
|
||||||
|
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(1) }
|
||||||
|
it { expect(subject['tous']).to eq(1) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
|
||||||
|
context 'and terminer dossiers on each of the others groups' do
|
||||||
|
let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) }
|
||||||
|
let!(:termine_dossier_on_gi_3) { create(:dossier, :accepte, groupe_instructeur: gi_3) }
|
||||||
|
|
||||||
|
before { subject }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(2) }
|
||||||
|
it { expect(subject['tous']).to eq(2) }
|
||||||
|
it { expect(subject['archives']).to eq(0) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an archives dossier' do
|
||||||
|
let!(:archives_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) }
|
||||||
|
|
||||||
|
it { expect(subject['a_suivre']).to eq(0) }
|
||||||
|
it { expect(subject['suivis']).to eq(0) }
|
||||||
|
it { expect(subject['traites']).to eq(0) }
|
||||||
|
it { expect(subject['tous']).to eq(0) }
|
||||||
|
it { expect(subject['archives']).to eq(1) }
|
||||||
|
|
||||||
|
context 'and terminer dossiers on each of the others groups' do
|
||||||
|
let!(:archives_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) }
|
||||||
|
let!(:archives_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3, archived: true) }
|
||||||
|
|
||||||
|
it { expect(subject['archives']).to eq(2) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def assign(procedure_to_assign, instructeur_assigne: instructeur)
|
def assign(procedure_to_assign, instructeur_assigne: instructeur)
|
||||||
|
|
|
@ -1030,136 +1030,4 @@ describe Procedure do
|
||||||
it { is_expected.to be false }
|
it { is_expected.to be false }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#dossiers_count_for_instructeur" do
|
|
||||||
let(:instructeur) { create(:instructeur) }
|
|
||||||
let(:procedure) { create(:procedure, instructeurs: [instructeur]) }
|
|
||||||
let(:gi_2) { procedure.groupe_instructeurs.create(label: '2') }
|
|
||||||
let(:gi_3) { procedure.groupe_instructeurs.create(label: '3') }
|
|
||||||
|
|
||||||
subject do
|
|
||||||
procedure.dossiers_count_for_instructeur(instructeur)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when logged in, and belonging to gi_1, gi_2" do
|
|
||||||
before do
|
|
||||||
instructeur.groupe_instructeurs << gi_2
|
|
||||||
end
|
|
||||||
|
|
||||||
context "without any dossier" do
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(0) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a new brouillon dossier' do
|
|
||||||
let!(:brouillon_dossier) { create(:dossier, procedure: procedure) }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(0) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a new dossier without follower' do
|
|
||||||
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(1) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(1) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
|
|
||||||
context 'and dossiers without follower on each of the others groups' do
|
|
||||||
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
|
|
||||||
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
|
|
||||||
|
|
||||||
before { subject }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(2) }
|
|
||||||
it { expect(subject['total']).to eq(2) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a new dossier with a follower' do
|
|
||||||
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
instructeur.followed_dossiers << new_followed_dossier
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(1) }
|
|
||||||
it { expect(subject['termines']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(1) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
|
|
||||||
context 'and dossier with a follower on each of the others groups' do
|
|
||||||
let!(:new_follow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2) }
|
|
||||||
let!(:new_follow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
instructeur.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3
|
|
||||||
end
|
|
||||||
|
|
||||||
# followed dossiers on another groupe should not be displayed
|
|
||||||
it { expect(subject['suivis']).to eq(2) }
|
|
||||||
it { expect(subject['total']).to eq(2) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'and dossier with a follower is unfollowed' do
|
|
||||||
before do
|
|
||||||
instructeur.unfollow(new_followed_dossier)
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(1) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(1) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a termine dossier' do
|
|
||||||
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(1) }
|
|
||||||
it { expect(subject['total']).to eq(1) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
|
|
||||||
context 'and terminer dossiers on each of the others groups' do
|
|
||||||
let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) }
|
|
||||||
let!(:termine_dossier_on_gi_3) { create(:dossier, :accepte, groupe_instructeur: gi_3) }
|
|
||||||
|
|
||||||
before { subject }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(2) }
|
|
||||||
it { expect(subject['total']).to eq(2) }
|
|
||||||
it { expect(subject['archived']).to eq(0) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with an archived dossier' do
|
|
||||||
let!(:archived_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) }
|
|
||||||
|
|
||||||
it { expect(subject['a_suivre']).to eq(0) }
|
|
||||||
it { expect(subject['suivis']).to eq(0) }
|
|
||||||
it { expect(subject['termines']).to eq(0) }
|
|
||||||
it { expect(subject['total']).to eq(0) }
|
|
||||||
it { expect(subject['archived']).to eq(1) }
|
|
||||||
|
|
||||||
context 'and terminer dossiers on each of the others groups' do
|
|
||||||
let!(:archived_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, archived: true) }
|
|
||||||
let!(:archived_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3, archived: true) }
|
|
||||||
|
|
||||||
it { expect(subject['archived']).to eq(2) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue