commit
c4f8b309fc
9 changed files with 106 additions and 79 deletions
|
@ -57,12 +57,13 @@ module Instructeurs
|
|||
@current_filters = current_filters
|
||||
@displayed_fields_options, @displayed_fields_selected = procedure_presentation.displayed_fields_for_select
|
||||
|
||||
@a_suivre_count, @suivis_count, @traites_count, @tous_count, @supprimes_recemment_count, @archives_count, @expirant_count = current_instructeur
|
||||
@counts = current_instructeur
|
||||
.dossiers_count_summary(groupe_instructeur_ids)
|
||||
.fetch_values('a_suivre', 'suivis', 'traites', 'tous', 'supprimes_recemment', 'archives', 'expirant')
|
||||
@can_download_dossiers = (@tous_count + @archives_count) > 0
|
||||
.symbolize_keys
|
||||
@can_download_dossiers = (@counts[:tous] + @counts[:archives]) > 0
|
||||
|
||||
dossiers = Dossier.where(groupe_instructeur_id: groupe_instructeur_ids)
|
||||
dossiers_count = @counts[statut.underscore.to_sym]
|
||||
|
||||
@followed_dossiers_id = current_instructeur
|
||||
.followed_dossiers
|
||||
|
@ -70,37 +71,12 @@ module Instructeurs
|
|||
.merge(dossiers.visible_by_administration)
|
||||
.pluck(:id)
|
||||
|
||||
@dossiers = dossiers.by_statut(current_instructeur, statut)
|
||||
dossiers_count = case statut
|
||||
when 'a-suivre'
|
||||
@a_suivre_count
|
||||
when 'suivis'
|
||||
@suivis_count
|
||||
when 'traites'
|
||||
@traites_count
|
||||
when 'tous'
|
||||
@tous_count
|
||||
when 'supprimes_recemment'
|
||||
@supprimes_recemment_count
|
||||
when 'archives'
|
||||
@archives_count
|
||||
when 'expirant'
|
||||
@expirant_count
|
||||
end
|
||||
|
||||
notifications = current_instructeur.notifications_for_groupe_instructeurs(groupe_instructeur_ids)
|
||||
@has_en_cours_notifications = notifications[:en_cours].present?
|
||||
@has_termine_notifications = notifications[:termines].present?
|
||||
@not_archived_notifications_dossier_ids = notifications[:en_cours] + notifications[:termines]
|
||||
|
||||
sorted_ids = procedure_presentation.sorted_ids(@dossiers, dossiers_count)
|
||||
|
||||
if @current_filters.count > 0
|
||||
filtered_ids = procedure_presentation.filtered_ids(@dossiers, statut)
|
||||
filtered_sorted_ids = sorted_ids.filter { |id| filtered_ids.include?(id) }
|
||||
else
|
||||
filtered_sorted_ids = sorted_ids
|
||||
end
|
||||
filtered_sorted_ids = procedure_presentation.filtered_sorted_ids(dossiers, dossiers_count, statut)
|
||||
|
||||
page = params[:page].presence || 1
|
||||
|
||||
|
|
|
@ -180,6 +180,17 @@ class ProcedurePresentation < ApplicationRecord
|
|||
end.reduce(:&)
|
||||
end
|
||||
|
||||
def filtered_sorted_ids(dossiers, count, statut)
|
||||
dossiers_by_statut = dossiers.by_statut(instructeur, statut)
|
||||
dossiers_sorted_ids = self.sorted_ids(dossiers_by_statut, count)
|
||||
|
||||
if filters[statut].present?
|
||||
filtered_ids(dossiers_by_statut, statut).intersection(dossiers_sorted_ids)
|
||||
else
|
||||
dossiers_sorted_ids
|
||||
end
|
||||
end
|
||||
|
||||
def human_value_for_filter(filter)
|
||||
case filter[TABLE]
|
||||
when TYPE_DE_CHAMP, TYPE_DE_CHAMP_PRIVATE
|
||||
|
|
|
@ -48,11 +48,11 @@ class ArchiveUploader
|
|||
params = blob_default_params(filepath).merge(byte_size: File.size(filepath),
|
||||
checksum: Digest::SHA256.file(filepath).hexdigest)
|
||||
blob = ActiveStorage::Blob.create_before_direct_upload!(**params)
|
||||
if syscall_to_custom_uploader(blob)
|
||||
if retryable_syscall_to_custom_uploader(blob)
|
||||
return blob
|
||||
else
|
||||
blob.purge
|
||||
fail "custom archive attachment failed, should it be retried ?"
|
||||
fail "custom archive attachment failed twice, retry later"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -73,6 +73,18 @@ class ArchiveUploader
|
|||
@namespaced_object_key ||= "archives/#{Date.today.strftime("%Y-%m-%d")}/#{SecureRandom.uuid}"
|
||||
end
|
||||
|
||||
def retryable_syscall_to_custom_uploader(blob)
|
||||
limit_to_retry = 1
|
||||
begin
|
||||
syscall_to_custom_uploader(blob)
|
||||
rescue
|
||||
if limit_to_retry > 0
|
||||
limit_to_retry = limit_to_retry - 1
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def syscall_to_custom_uploader(blob)
|
||||
system(ENV.fetch('ACTIVE_STORAGE_BIG_FILE_UPLOADER_WITH_ENCRYPTION_PATH').to_s, filepath, blob.key, exception: true)
|
||||
end
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
|
||||
.container.flex= render partial: "tabs", locals: { procedure: @procedure,
|
||||
statut: @statut,
|
||||
a_suivre_count: @a_suivre_count,
|
||||
suivis_count: @suivis_count,
|
||||
traites_count: @traites_count,
|
||||
tous_count: @tous_count,
|
||||
supprimes_recemment_count: @supprimes_recemment_count,
|
||||
archives_count: @archives_count,
|
||||
expirant_count: @expirant_count,
|
||||
a_suivre_count: @counts[:a_suivre],
|
||||
suivis_count: @counts[:suivis],
|
||||
traites_count: @counts[:traites],
|
||||
tous_count: @counts[:tous],
|
||||
supprimes_recemment_count: @counts[:supprimes_recemment],
|
||||
archives_count: @counts[:archives],
|
||||
expirant_count: @counts[:expirant],
|
||||
has_en_cours_notifications: @has_en_cours_notifications,
|
||||
has_termine_notifications: @has_termine_notifications }
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
class AddUniqIndexOnAttestationDossierId < ActiveRecord::Migration[6.1]
|
||||
include Database::MigrationHelpers
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
remove_index :attestations, :dossier_id
|
||||
add_concurrent_index :attestations, :dossier_id, unique: true
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_03_23_120846) do
|
||||
ActiveRecord::Schema.define(version: 2022_04_05_100354) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -134,7 +134,7 @@ ActiveRecord::Schema.define(version: 2022_03_23_120846) do
|
|||
t.integer "dossier_id", null: false
|
||||
t.string "title"
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["dossier_id"], name: "index_attestations_on_dossier_id"
|
||||
t.index ["dossier_id"], name: "index_attestations_on_dossier_id", unique: true
|
||||
end
|
||||
|
||||
create_table "avis", id: :serial, force: :cascade do |t|
|
||||
|
|
|
@ -273,21 +273,24 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
context 'with a new dossier without follower' do
|
||||
let!(:new_unfollow_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||
|
||||
before { subject }
|
||||
it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier]) }
|
||||
context do
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'with a dossier en contruction hidden by user' do
|
||||
let!(:hidden_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2, hidden_by_user_at: 1.hour.ago) }
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'with a dossier en contruction not hidden by user' do
|
||||
let!(:en_construction_dossier) { create(:dossier, :en_construction, groupe_instructeur: gi_2) }
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier, en_construction_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier, en_construction_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'and dossiers without follower on each of the others groups' do
|
||||
|
@ -296,32 +299,27 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_unfollow_dossier, new_unfollow_dossier_on_gi_2].map(&:id)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a new dossier with a follower' do
|
||||
let(:statut) { 'suivis' }
|
||||
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||
let!(:new_followed_dossier) { create(:dossier, :en_instruction, procedure: procedure, followers_instructeurs: [instructeur]) }
|
||||
|
||||
before do
|
||||
instructeur.followed_dossiers << new_followed_dossier
|
||||
subject
|
||||
context do
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([new_followed_dossier]) }
|
||||
|
||||
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) }
|
||||
let!(:new_follow_dossier_on_gi_2) { create(:dossier, :en_instruction, groupe_instructeur: gi_2, followers_instructeurs: [instructeur]) }
|
||||
let!(:new_follow_dossier_on_gi_3) { create(:dossier, :en_instruction, groupe_instructeur: gi_3, followers_instructeurs: [instructeur]) }
|
||||
|
||||
before do
|
||||
instructeur.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3
|
||||
subject
|
||||
end
|
||||
before { subject }
|
||||
|
||||
# followed dossiers on another groupe should not be displayed
|
||||
it { expect(assigns(:dossiers)).to contain_exactly(new_followed_dossier, new_follow_dossier_on_gi_2) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier, new_follow_dossier_on_gi_2].map(&:id)) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -329,9 +327,11 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
let(:statut) { 'traites' }
|
||||
let!(:termine_dossier) { create(:dossier, :accepte, procedure: procedure) }
|
||||
|
||||
before { subject }
|
||||
context do
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([termine_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'and terminer dossiers on each of the others groups' do
|
||||
let!(:termine_dossier_on_gi_2) { create(:dossier, :accepte, groupe_instructeur: gi_2) }
|
||||
|
@ -339,7 +339,7 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([termine_dossier, termine_dossier_on_gi_2]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier, termine_dossier_on_gi_2].map(&:id)) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -348,9 +348,11 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
let!(:archived_dossier) { create(:dossier, :en_instruction, procedure: procedure, archived: true) }
|
||||
let!(:archived_dossier_deleted) { create(:dossier, :en_instruction, procedure: procedure, archived: true, hidden_by_administration_at: 2.days.ago) }
|
||||
|
||||
before { subject }
|
||||
context do
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([archived_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
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) }
|
||||
|
@ -358,7 +360,7 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([archived_dossier, archived_dossier_on_gi_2]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier, archived_dossier_on_gi_2].map(&:id)) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -370,7 +372,7 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
|
||||
before { subject }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([expiring_dossier_termine, expiring_dossier_en_construction]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([expiring_dossier_termine, expiring_dossier_en_construction].map(&:id)) }
|
||||
end
|
||||
|
||||
describe 'statut' do
|
||||
|
@ -387,7 +389,7 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
context 'when statut is empty' do
|
||||
let(:statut) { nil }
|
||||
|
||||
it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier].map(&:id)) }
|
||||
it { expect(assigns(:statut)).to eq('a-suivre') }
|
||||
end
|
||||
|
||||
|
@ -395,35 +397,35 @@ describe Instructeurs::ProceduresController, type: :controller do
|
|||
let(:statut) { 'a-suivre' }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('a-suivre') }
|
||||
it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'when statut is suivis' do
|
||||
let(:statut) { 'suivis' }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('suivis') }
|
||||
it { expect(assigns(:dossiers)).to match_array([new_followed_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([new_followed_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'when statut is traites' do
|
||||
let(:statut) { 'traites' }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('traites') }
|
||||
it { expect(assigns(:dossiers)).to match_array([termine_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([termine_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'when statut is tous' do
|
||||
let(:statut) { 'tous' }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('tous') }
|
||||
it { expect(assigns(:dossiers)).to match_array([a_suivre_dossier, new_followed_dossier, termine_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([a_suivre_dossier, new_followed_dossier, termine_dossier].map(&:id)) }
|
||||
end
|
||||
|
||||
context 'when statut is archives' do
|
||||
let(:statut) { 'archives' }
|
||||
|
||||
it { expect(assigns(:statut)).to eq('archives') }
|
||||
it { expect(assigns(:dossiers)).to match_array([archived_dossier]) }
|
||||
it { expect(assigns(:filtered_sorted_paginated_ids)).to match_array([archived_dossier].map(&:id)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1480,12 +1480,10 @@ describe Dossier do
|
|||
before do
|
||||
create(:dossier, transfer: transfer)
|
||||
create(:attestation, dossier: dossier)
|
||||
create(:attestation, dossier: dossier)
|
||||
end
|
||||
|
||||
it "can destroy dossier with two attestations" do
|
||||
it "can destroy dossier" do
|
||||
expect(dossier.destroy).to be_truthy
|
||||
expect(transfer.reload).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -57,14 +57,33 @@ describe ProcedureArchiveService do
|
|||
let(:fake_blob_bytesize) { 100.gigabytes }
|
||||
|
||||
before do
|
||||
expect(uploader).to receive(:syscall_to_custom_uploader).and_return(true)
|
||||
expect(File).to receive(:size).with(file.path).and_return(fake_blob_bytesize)
|
||||
expect(Digest::SHA256).to receive(:file).with(file.path).and_return(double(hexdigest: fake_blob_checksum.hexdigest))
|
||||
end
|
||||
|
||||
it 'creates a blob' do
|
||||
expect { uploader.send(:upload_with_chunking_wrapper) }
|
||||
.to change { ActiveStorage::Blob.where(checksum: fake_blob_checksum.hexdigest, byte_size: fake_blob_bytesize).count }.by(1)
|
||||
context 'when it just works' do
|
||||
it 'creates a blob' do
|
||||
expect(uploader).to receive(:syscall_to_custom_uploader).and_return(true)
|
||||
expect { uploader.send(:upload_with_chunking_wrapper) }
|
||||
.to change { ActiveStorage::Blob.where(checksum: fake_blob_checksum.hexdigest, byte_size: fake_blob_bytesize).count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it fails once (DS proxy a bit flacky with archive ±>20Go, fails once, accept other call' do
|
||||
it 'retries' do
|
||||
expect(uploader).to receive(:syscall_to_custom_uploader).with(anything).once.and_raise(StandardError, "BOOM")
|
||||
expect(uploader).to receive(:syscall_to_custom_uploader).with(anything).once.and_return(true)
|
||||
expect { uploader.send(:upload_with_chunking_wrapper) }
|
||||
.to change { ActiveStorage::Blob.where(checksum: fake_blob_checksum.hexdigest, byte_size: fake_blob_bytesize).count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it fails twice' do
|
||||
it 'does not retry more than once' do
|
||||
expect(uploader).to receive(:syscall_to_custom_uploader).with(anything).twice.and_raise(StandardError, "BOOM")
|
||||
expect { uploader.send(:upload_with_chunking_wrapper) }
|
||||
.to raise_error(RuntimeError, "custom archive attachment failed twice, retry later")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue