Merge pull request #9610 from mfo/US/fix-missing-champs
correctif(data): tâche rake recréant les champs manquant à un dossier ayant subi une perte de données
This commit is contained in:
commit
8a4299ade1
6 changed files with 183 additions and 31 deletions
|
@ -1,4 +1,4 @@
|
|||
class PhoneFixer
|
||||
class DataFixer::ChampsPhoneInvalid
|
||||
def self.fix(phones_string)
|
||||
phone_candidates = phones_string
|
||||
.split(/-/)
|
81
app/lib/data_fixer/dossier_champs_missing.rb
Normal file
81
app/lib/data_fixer/dossier_champs_missing.rb
Normal file
|
@ -0,0 +1,81 @@
|
|||
# some race condition (regarding double submit of dossier.passer_en_construction!) might remove champs
|
||||
# until now we haven't decided to push a stronger fix than an UI change
|
||||
# so we might have to recreate some deleted champs and notify administration
|
||||
class DataFixer::DossierChampsMissing
|
||||
def fix
|
||||
fixed_on_origin = apply_fix(@original_dossier)
|
||||
|
||||
fixed_on_other = Dossier.where(editing_fork_origin_id: @original_dossier.id)
|
||||
.map(&method(:apply_fix))
|
||||
|
||||
[fixed_on_origin, fixed_on_other.sum].sum
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :original_dossier
|
||||
|
||||
def initialize(dossier:)
|
||||
@original_dossier = dossier
|
||||
end
|
||||
|
||||
def apply_fix(dossier)
|
||||
added_champs_root = fix_champs_root(dossier)
|
||||
added_champs_in_repetition = fix_champs_in_repetition(dossier)
|
||||
|
||||
added_champs = added_champs_root + added_champs_in_repetition
|
||||
if !added_champs.empty?
|
||||
dossier.save!
|
||||
log_champs_added(dossier, added_champs)
|
||||
added_champs.size
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def fix_champs_root(dossier)
|
||||
champs_root, _ = dossier.champs.partition { _1.parent_id.blank? }
|
||||
expected_tdcs = dossier.revision.revision_types_de_champ.filter { _1.parent.blank? }.map(&:type_de_champ)
|
||||
|
||||
expected_tdcs.filter { !champs_root.map(&:stable_id).include?(_1.stable_id) }
|
||||
.map do |missing_tdc|
|
||||
champ_root_missing = missing_tdc.build_champ
|
||||
|
||||
dossier.champs_public << champ_root_missing
|
||||
champ_root_missing
|
||||
end
|
||||
end
|
||||
|
||||
def fix_champs_in_repetition(dossier)
|
||||
champs_repetition, _ = dossier.champs.partition(&:repetition?)
|
||||
|
||||
champs_repetition.flat_map do |champ_repetition|
|
||||
champ_repetition_missing = champ_repetition.rows.flat_map do |row|
|
||||
row_id = row.first.row_id
|
||||
expected_tdcs = dossier.revision.children_of(champ_repetition.type_de_champ)
|
||||
row_tdcs = row.map(&:type_de_champ)
|
||||
|
||||
(expected_tdcs - row_tdcs).map do |missing_tdc|
|
||||
champ_repetition_missing = missing_tdc.build_champ(row_id: row_id)
|
||||
champ_repetition.champs << champ_repetition_missing
|
||||
champ_repetition_missing
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def log_champs_added(dossier, added_champs)
|
||||
app_traces = caller.reject { _1.match?(%r{/ruby/.+/gems/}) }.map { _1.sub(Rails.root.to_s, "") }
|
||||
|
||||
payload = {
|
||||
message: "DataFixer::DossierChampsMissing",
|
||||
dossier_id: dossier.id,
|
||||
champs_ids: added_champs.map(&:id).join(","),
|
||||
caller: app_traces
|
||||
}
|
||||
|
||||
logger = Lograge.logger || Rails.logger
|
||||
|
||||
logger.info payload.to_json
|
||||
end
|
||||
end
|
44
lib/tasks/data_fixer.rake
Normal file
44
lib/tasks/data_fixer.rake
Normal file
|
@ -0,0 +1,44 @@
|
|||
require Rails.root.join("lib", "tasks", "task_helper")
|
||||
|
||||
namespace :data_fixer do
|
||||
desc <<~EOD
|
||||
Given a procedure_id in argument, run the DataFixer::ChampsPhoneInvalid.
|
||||
ex: rails data_fixer:fix_phones\[1\]
|
||||
EOD
|
||||
task :fix_phones, [:procedure_id] => :environment do |_t, args|
|
||||
procedure = Procedure.find(args[:procedure_id])
|
||||
|
||||
phone_champs = Champ
|
||||
.where(dossier_id: procedure.dossiers.pluck(:id))
|
||||
.where(type: "Champs::PhoneChamp")
|
||||
|
||||
invalid_phone_champs = phone_champs.reject(&:valid?)
|
||||
|
||||
fixable_phone_champs = invalid_phone_champs.filter { |phone| DataFixer::ChampsPhoneInvalid.fixable?(phone.value) }
|
||||
|
||||
fixable_phone_champs.each do |phone|
|
||||
fixable_phone_value = phone.value
|
||||
fixed_phone_value = DataFixer::ChampsPhoneInvalid.fix(fixable_phone_value)
|
||||
if phone.update(value: fixed_phone_value)
|
||||
rake_puts "Invalid phone #{fixable_phone_value} is fixed as #{fixed_phone_value}"
|
||||
else
|
||||
rake_puts "Failed to fix #{fixable_phone_value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc <<~EOD
|
||||
Given a dossier_id in argument, run the DossierChampsMissing.
|
||||
ex: rails data_fixer:dossier_missing_champ\[1\]
|
||||
EOD
|
||||
task :dossier_missing_champ, [:dossier_id] => :environment do |_t, args|
|
||||
dossier = Dossier.find(args[:dossier_id])
|
||||
result = DataFixer::DossierChampsMissing.new(dossier:).fix
|
||||
|
||||
if result > 0
|
||||
rake_puts "Dossier#[#{args[:dossier_id]}] fixed"
|
||||
else
|
||||
rake_puts "Dossier#[#{args[:dossier_id]}] not fixed"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
require Rails.root.join("lib", "tasks", "task_helper")
|
||||
|
||||
namespace :phone_fixer do
|
||||
desc <<~EOD
|
||||
Given a procedure_id in argument, run the PhoneFixer.
|
||||
ex: rails phone_fixer:run\[1\]
|
||||
EOD
|
||||
task :run, [:procedure_id] => :environment do |_t, args|
|
||||
procedure = Procedure.find(args[:procedure_id])
|
||||
|
||||
phone_champs = Champ
|
||||
.where(dossier_id: procedure.dossiers.pluck(:id))
|
||||
.where(type: "Champs::PhoneChamp")
|
||||
|
||||
invalid_phone_champs = phone_champs.reject(&:valid?)
|
||||
|
||||
fixable_phone_champs = invalid_phone_champs.filter { |phone| PhoneFixer.fixable?(phone.value) }
|
||||
|
||||
fixable_phone_champs.each do |phone|
|
||||
fixable_phone_value = phone.value
|
||||
fixed_phone_value = PhoneFixer.fix(fixable_phone_value)
|
||||
if phone.update(value: fixed_phone_value)
|
||||
rake_puts "Invalid phone #{fixable_phone_value} is fixed as #{fixed_phone_value}"
|
||||
else
|
||||
rake_puts "Failed to fix #{fixable_phone_value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
describe PhoneFixer do
|
||||
describe DataFixer::ChampsPhoneInvalid do
|
||||
describe '#fix' do
|
||||
subject { described_class.fix(phone_str) }
|
||||
|
56
spec/lib/data_fixer/dossier_champs_missing_spec.rb
Normal file
56
spec/lib/data_fixer/dossier_champs_missing_spec.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
describe DataFixer::DossierChampsMissing do
|
||||
describe '#fix' do
|
||||
let(:procedure) { create(:procedure, :with_datetime, :with_dossier_link) }
|
||||
let(:dossier) { create(:dossier, procedure:) }
|
||||
|
||||
context 'when dossier does not have a fork' do
|
||||
before { dossier.champs_public.first.destroy }
|
||||
subject { described_class.new(dossier:).fix }
|
||||
|
||||
it 'add missing champs to the dossier' do
|
||||
expect { subject }.to change { dossier.champs_public.count }.from(1).to(2)
|
||||
end
|
||||
|
||||
it 'returns number of added champs' do
|
||||
expect(subject).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when dossier have a fork' do
|
||||
before { dossier.champs_public.first.destroy }
|
||||
let(:create_fork) { dossier.find_or_create_editing_fork(dossier.user) }
|
||||
subject do
|
||||
create_fork
|
||||
described_class.new(dossier:).fix
|
||||
end
|
||||
|
||||
it 'add missing champs to the fork too' do
|
||||
expect { subject }.to change { create_fork.champs_public.count }.from(1).to(2)
|
||||
end
|
||||
|
||||
it 'sums number of added champs for dossier and editing_fork_origin_id' do
|
||||
expect(subject).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when dossier have missing champ on repetition' do
|
||||
let(:procedure) { create(:procedure, :with_repetition) }
|
||||
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
|
||||
let(:champ_repetition) { dossier.champs_public.first }
|
||||
let(:initial_champ_count) { dossier.champs.count }
|
||||
before do
|
||||
initial_champ_count
|
||||
champ_repetition.champs.first.destroy
|
||||
end
|
||||
subject { described_class.new(dossier:).fix }
|
||||
|
||||
it 'add missing champs to repetition' do
|
||||
expect { subject }.to change { dossier.champs.count }.from(initial_champ_count - 1).to(initial_champ_count)
|
||||
end
|
||||
|
||||
it 'counts number of added champs for dossier.repetitions' do
|
||||
expect(subject).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue