Merge pull request #6896 from betagouv/main

2022-02-04-01
This commit is contained in:
Kara Diaby 2022-02-04 10:04:40 +01:00 committed by GitHub
commit 8b9691cca1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 114 additions and 66 deletions

View file

@ -4,8 +4,7 @@ class RechercheController < ApplicationController
PROJECTIONS = [ PROJECTIONS = [
{ "table" => 'procedure', "column" => 'libelle' }, { "table" => 'procedure', "column" => 'libelle' },
{ "table" => 'user', "column" => 'email' }, { "table" => 'user', "column" => 'email' },
{ "table" => 'procedure', "column" => 'procedure_id' }, { "table" => 'procedure', "column" => 'procedure_id' }
{ "table" => 'dossier', "column" => 'hidden_by_administration_at' }
] ]
def index def index

View file

@ -31,7 +31,7 @@ class StatsController < ApplicationController
@procedures_in_the_last_4_months = last_four_months_serie(procedures, :published_at) @procedures_in_the_last_4_months = last_four_months_serie(procedures, :published_at)
@dossiers_cumulative = stat.dossiers_cumulative @dossiers_cumulative = stat.dossiers_cumulative
@dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months @dossiers_in_the_last_4_months = format_keys_as_months(stat.dossiers_in_the_last_4_months)
end end
def download def download
@ -136,11 +136,18 @@ class StatsController < ApplicationController
end end
end end
def format_keys_as_months(series)
series.transform_keys do |k|
date = k.is_a?(Date) ? k : (Date.parse(k) rescue k)
l(date, format: "%B %Y")
end
end
def last_four_months_serie(association, date_attribute) def last_four_months_serie(association, date_attribute)
association series = association
.group_by_month(date_attribute, last: 4, current: super_admin_signed_in?) .group_by_month(date_attribute, last: 4, current: super_admin_signed_in?)
.count .count
.transform_keys { |date| l(date, format: "%B %Y") } format_keys_as_months(series)
end end
def cumulative_month_serie(association, date_attribute) def cumulative_month_serie(association, date_attribute)

View file

@ -1,5 +1,6 @@
module StringToHtmlHelper module StringToHtmlHelper
def string_to_html(str, wrapper_tag = 'p') def string_to_html(str, wrapper_tag = 'p')
return nil if str.blank?
html_formatted = simple_format(str, {}, { wrapper_tag: wrapper_tag }) html_formatted = simple_format(str, {}, { wrapper_tag: wrapper_tag })
with_links = Anchored::Linker.auto_link(html_formatted, target: '_blank', rel: 'noopener') with_links = Anchored::Linker.auto_link(html_formatted, target: '_blank', rel: 'noopener')
sanitize(with_links, attributes: ['target', 'rel', 'href']) sanitize(with_links, attributes: ['target', 'rel', 'href'])

View file

@ -80,11 +80,7 @@ class Stat < ApplicationRecord
association.group_by_month(date_attribute, last: 4, current: false).count association.group_by_month(date_attribute, last: 4, current: false).count
end end
month_serie(sum_hashes(*timeseries)) sum_hashes(*timeseries).sort.to_h
end
def month_serie(date_serie)
date_serie.keys.sort.each_with_object({}) { |date, h| h[I18n.l(date, format: "%B %Y")] = date_serie[date] }
end end
def cumulative_month_serie(associations_with_date_attribute) def cumulative_month_serie(associations_with_date_attribute)

View file

@ -1,5 +1,5 @@
class DossierProjectionService class DossierProjectionService
class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :columns) class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :hidden_by_administration_at, :columns)
end end
TABLE = 'table' TABLE = 'table'
@ -21,8 +21,8 @@ class DossierProjectionService
state_field = { TABLE => 'self', COLUMN => 'state' } state_field = { TABLE => 'self', COLUMN => 'state' }
archived_field = { TABLE => 'self', COLUMN => 'archived' } archived_field = { TABLE => 'self', COLUMN => 'archived' }
hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' } hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' }
hidden_by_administration_at_field = { TABLE => 'self', COLUMN => 'hidden_by_administration_at' }
([state_field, archived_field, hidden_by_user_at_field] + fields) # the view needs state and archived dossier attributes ([state_field, archived_field, hidden_by_user_at_field, hidden_by_administration_at_field] + fields) # the view needs state and archived dossier attributes
.each { |f| f[:id_value_h] = {} } .each { |f| f[:id_value_h] = {} }
.group_by { |f| f[TABLE] } # one query per table .group_by { |f| f[TABLE] } # one query per table
.each do |table, fields| .each do |table, fields|
@ -46,7 +46,7 @@ class DossierProjectionService
.pluck(:id, *fields.map { |f| f[COLUMN].to_sym }) .pluck(:id, *fields.map { |f| f[COLUMN].to_sym })
.each do |id, *columns| .each do |id, *columns|
fields.zip(columns).each do |field, value| fields.zip(columns).each do |field, value|
if [state_field, archived_field, hidden_by_user_at_field].include?(field) if [state_field, archived_field, hidden_by_user_at_field, hidden_by_administration_at_field].include?(field)
field[:id_value_h][id] = value field[:id_value_h][id] = value
else else
field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime
@ -100,6 +100,7 @@ class DossierProjectionService
state_field[:id_value_h][dossier_id], state_field[:id_value_h][dossier_id],
archived_field[:id_value_h][dossier_id], archived_field[:id_value_h][dossier_id],
hidden_by_user_at_field[:id_value_h][dossier_id], hidden_by_user_at_field[:id_value_h][dossier_id],
hidden_by_administration_at_field[:id_value_h][dossier_id],
fields.map { |f| f[:id_value_h][dossier_id] } fields.map { |f| f[:id_value_h][dossier_id] }
) )
end end

View file

@ -28,8 +28,7 @@
state: dossier.state, state: dossier.state,
archived: dossier.archived, archived: dossier.archived,
dossier_is_followed: current_instructeur&.follow?(dossier), dossier_is_followed: current_instructeur&.follow?(dossier),
close_to_expiration: dossier.close_to_expiration?, close_to_expiration: dossier.close_to_expiration? }
recently_deleted: dossier.hidden_by_administration? }
.state-button .state-button

View file

@ -21,13 +21,7 @@
%span.icon.archive %span.icon.archive
.dropdown-description .dropdown-description
Archiver le dossier Archiver le dossier
- if recently_deleted
%li.danger
= link_to restore_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, data: { confirm: "Voulez vous vraiment restaurer le dossier #{dossier_id}" } do
%span.icon.reply
.dropdown-description
= t('views.instructeurs.dossiers.restore')
- else
%li.danger %li.danger
= link_to supprimer_dossier_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier_id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do = link_to supprimer_dossier_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, data: { confirm: "Voulez vous vraiment supprimer le dossier #{dossier_id} ? Cette action est irréversible. \nNous vous suggérons de télécharger le dossier au format PDF au préalable." } do
%span.icon.delete %span.icon.delete

View file

@ -132,14 +132,19 @@
%td.status-col %td.status-col
%a.cell-link{ href: path }= status_badge(p.state) %a.cell-link{ href: path }= status_badge(p.state)
- if @statut == 'supprimes_recemment'
%td.action-col.follow-col
= link_to restore_instructeur_dossier_path(@procedure, p.dossier_id), method: :patch, class: "button primary" do
= t('views.instructeurs.dossiers.restore')
- else
%td.action-col.follow-col= render partial: 'dossier_actions', %td.action-col.follow-col= render partial: 'dossier_actions',
locals: { procedure_id: @procedure.id, locals: { procedure_id: @procedure.id,
dossier_id: p.dossier_id, dossier_id: p.dossier_id,
state: p.state, state: p.state,
archived: p.archived, archived: p.archived,
dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id), dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id),
close_to_expiration: @statut == 'expirant', close_to_expiration: @statut == 'expirant' }
recently_deleted: @statut == 'supprimes_recemment' }
= pagination = pagination
- else - else

View file

@ -0,0 +1,17 @@
%td.folder-col
%p.cell-link
%span.icon.folder
%td.number-col
%p.cell-link= p.dossier_id
%td
%p.cell-link= procedure_libelle
%td
%p.cell-link
= user_email
= "- #{t('views.instructeurs.dossiers.deleted_by_administration')}" if p.hidden_by_administration_at.present?
%td.status-col
%p.cell-link= status_badge(p.state)

View file

@ -20,13 +20,14 @@
%th.action-col.follow-col %th.action-col.follow-col
%tbody %tbody
- @projected_dossiers.each do |p| - @projected_dossiers.each do |p|
- procedure_libelle, user_email, procedure_id, hidden_by_administration = p.columns - procedure_libelle, user_email, procedure_id = p.columns
- instructeur_dossier = @instructeur_dossiers_ids.include?(p.dossier_id) - instructeur_dossier = @instructeur_dossiers_ids.include?(p.dossier_id)
- expert_dossier = @dossier_avis_ids_h[p.dossier_id].present? - expert_dossier = @dossier_avis_ids_h[p.dossier_id].present?
- hidden_by_administration = p.hidden_by_administration_at.present?
- instructeur_and_expert_dossier = instructeur_dossier && expert_dossier - instructeur_and_expert_dossier = instructeur_dossier && expert_dossier
- path = instructeur_dossier ? instructeur_dossier_path(procedure_id, p.dossier_id) : expert_avis_path(procedure_id, @dossier_avis_ids_h[p.dossier_id]) - path = instructeur_dossier ? instructeur_dossier_path(procedure_id, p.dossier_id) : expert_avis_path(procedure_id, @dossier_avis_ids_h[p.dossier_id])
%tr %tr{ class: [p.hidden_by_administration_at.present? && "file-hidden-by-user"] }
- if instructeur_and_expert_dossier - if instructeur_and_expert_dossier
%td.folder-col.cell-link %td.folder-col.cell-link
%span.icon.folder %span.icon.folder
@ -39,7 +40,11 @@
%td.status-col %td.status-col
.cell-link= status_badge(p.state) .cell-link= status_badge(p.state)
- elsif hidden_by_administration
= render partial: "recherche/hidden_dossier", locals: {p: p, procedure_libelle: procedure_libelle, user_email: user_email}
- else - else
%td.folder-col %td.folder-col
%a.cell-link{ href: path } %a.cell-link{ href: path }
%span.icon.folder %span.icon.folder
@ -76,14 +81,19 @@
Donner mon avis Donner mon avis
- elsif instructeur_dossier - elsif instructeur_dossier
- if hidden_by_administration
%td.action-col.follow-col
= link_to restore_instructeur_dossier_path(procedure_id, p.dossier_id), method: :patch, class: "button primary" do
= t('views.instructeurs.dossiers.restore')
- else
%td.action-col.follow-col= render partial: "instructeurs/procedures/dossier_actions", %td.action-col.follow-col= render partial: "instructeurs/procedures/dossier_actions",
locals: { procedure_id: procedure_id, locals: { procedure_id: procedure_id,
dossier_id: p.dossier_id, dossier_id: p.dossier_id,
state: p.state, state: p.state,
archived: p.archived, archived: p.archived,
dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id), dossier_is_followed: @followed_dossiers_id.include?(p.dossier_id),
close_to_expiration: nil, close_to_expiration: nil }
recently_deleted: hidden_by_administration.blank? }
- else - else
%td %td

View file

@ -29,6 +29,7 @@
%p.attachment-error-title %p.attachment-error-title
Une erreur sest produite pendant lenvoi du fichier. Une erreur sest produite pendant lenvoi du fichier.
%p.attachment-error-description %p.attachment-error-description
Une erreur inconnue s'est produite pendant l'envoi du fichier
= button_tag type: 'button', class: 'button attachment-error-retry', data: { 'input-target': ".attachment-input-#{attachment_id}" } do = button_tag type: 'button', class: 'button attachment-error-retry', data: { 'input-target': ".attachment-input-#{attachment_id}" } do
%span.icon.retry %span.icon.retry
Ré-essayer Ré-essayer

View file

@ -57,7 +57,7 @@
- when TypeDeChamp.type_champs.fetch(:number) - when TypeDeChamp.type_champs.fetch(:number)
= number_with_html_delimiter(c.to_s) = number_with_html_delimiter(c.to_s)
- else - else
= format_text_value(c.to_s) = format_text_value(c.to_s) unless c.blank?
- if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section) - if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section)
%td.updated-at %td.updated-at

View file

@ -140,7 +140,8 @@ en:
archived_dossier: "This file will be kept for an additional month" archived_dossier: "This file will be kept for an additional month"
delete_dossier: "Delete file" delete_dossier: "Delete file"
deleted_by_user: "File deleted by user" deleted_by_user: "File deleted by user"
restore: "Restore the file" deleted_by_administration: "File deleted by administration"
restore: "Restore"
avis: avis:
introduction_file_explaination: "File attached to the request for advice" introduction_file_explaination: "File attached to the request for advice"
users: users:

View file

@ -137,7 +137,8 @@ fr:
archived_dossier: "Le dossier sera conservé 1 mois supplémentaire" archived_dossier: "Le dossier sera conservé 1 mois supplémentaire"
delete_dossier: "Supprimer le dossier" delete_dossier: "Supprimer le dossier"
deleted_by_user: "Dossier supprimé par l'usager" deleted_by_user: "Dossier supprimé par l'usager"
restore: "Restaurer le dossier" deleted_by_administration: "Dossier supprimé par l'administration"
restore: "Restaurer"
avis: avis:
introduction_file_explaination: "Fichier joint à la demande davis" introduction_file_explaination: "Fichier joint à la demande davis"
users: users:

View file

@ -28,7 +28,7 @@ RSpec.describe StringToHtmlHelper, type: :helper do
context "with empty decription" do context "with empty decription" do
let(:description) { nil } let(:description) { nil }
it { is_expected.to eq('<p></p>') } it { is_expected.to eq nil }
end end
context "with a bad script" do context "with a bad script" do

View file

@ -57,24 +57,30 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end end
rs = Stat.send(:cumulative_month_serie, [ s = Stat.new({
dossiers_cumulative:
Stat.send(:cumulative_month_serie, [
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]) ])
expect(rs).to eq({ })
12 => 2, s.save!
11 => 4, s.reload
10 => 6, # Use `Hash#to_a` to also test the key ordering
9 => 8, expect(s.dossiers_cumulative.to_a).to eq([
8 => 10, [formatted_n_months_ago(12), 2],
7 => 12, [formatted_n_months_ago(11), 4],
6 => 14, [formatted_n_months_ago(10), 6],
5 => 16, [formatted_n_months_ago(9), 8],
4 => 18, [formatted_n_months_ago(8), 10],
3 => 20, [formatted_n_months_ago(7), 12],
2 => 22, [formatted_n_months_ago(6), 14],
1 => 24 [formatted_n_months_ago(5), 16],
}.transform_keys { |i| i.months.ago.beginning_of_month.to_date }) [formatted_n_months_ago(4), 18],
[formatted_n_months_ago(3), 20],
[formatted_n_months_ago(2), 22],
[formatted_n_months_ago(1), 24]
])
end end
end end
@ -85,16 +91,22 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end end
rs = Stat.send(:last_four_months_serie, [ s = Stat.new({
dossiers_in_the_last_4_months:
Stat.send(:last_four_months_serie, [
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]) ])
expect(rs).to eq({
"juillet 2021" => 2,
"août 2021" => 2,
"septembre 2021" => 2,
"octobre 2021" => 2
}) })
s.save!
s.reload
# Use `Hash#to_a` to also test the key ordering
expect(s.dossiers_in_the_last_4_months.to_a).to eq([
['2021-07-01', 2],
['2021-08-01', 2],
['2021-09-01', 2],
['2021-10-01', 2]
])
end end
end end
end end
@ -104,4 +116,8 @@ describe Stat do
expect(Stat.send(:sum_hashes, *[{ a: 1, b: 2, d: 5 }, { a: 2, b: 3, c: 5 }])).to eq({ a: 3, b: 5, c: 5, d: 5 }) expect(Stat.send(:sum_hashes, *[{ a: 1, b: 2, d: 5 }, { a: 2, b: 3, c: 5 }])).to eq({ a: 3, b: 5, c: 5, d: 5 })
end end
end end
def formatted_n_months_ago(i)
i.months.ago.beginning_of_month.to_date.to_s
end
end end