diff --git a/app/lib/recovery/revision_exporter.rb b/app/lib/recovery/revision_exporter.rb new file mode 100644 index 000000000..fdbbfb40d --- /dev/null +++ b/app/lib/recovery/revision_exporter.rb @@ -0,0 +1,17 @@ +module Recovery + class RevisionExporter + FILE_PATH = Rails.root.join('lib', 'data', 'revision', 'export.dump') + + attr_reader :revisions, :file_path + def initialize(revision_ids:, file_path: FILE_PATH) + @revisions = ProcedureRevision.where(id: revision_ids) + .preload(revision_types_de_champ: :type_de_champ) + .to_a + @file_path = file_path + end + + def dump + @file_path.binwrite(Marshal.dump(@revisions)) + end + end +end diff --git a/app/lib/recovery/revision_importer.rb b/app/lib/recovery/revision_importer.rb new file mode 100644 index 000000000..ab13d7040 --- /dev/null +++ b/app/lib/recovery/revision_importer.rb @@ -0,0 +1,22 @@ +module Recovery + class RevisionImporter + attr_reader :revisions + + def initialize(file_path: Recovery::RevisionExporter::FILE_PATH) + # rubocop:disable Security/MarshalLoad + @revisions = Marshal.load(File.read(file_path)) + # rubocop:enable Security/MarshalLoad + end + + def load + @revisions.each do |revision| + ProcedureRevisionTypeDeChamp.transaction do + revision.revision_types_de_champ.each do |coordinate| + ProcedureRevisionTypeDeChamp.upsert(coordinate.attributes) + TypeDeChamp.upsert(coordinate.type_de_champ.attributes.except('type_champs')) + end + end + end + end + end +end diff --git a/spec/lib/recovery/life_cycle_spec.rb b/spec/lib/recovery/dossier_life_cycle_spec.rb similarity index 99% rename from spec/lib/recovery/life_cycle_spec.rb rename to spec/lib/recovery/dossier_life_cycle_spec.rb index a0b8354b4..8cc25fbbf 100644 --- a/spec/lib/recovery/life_cycle_spec.rb +++ b/spec/lib/recovery/dossier_life_cycle_spec.rb @@ -1,4 +1,4 @@ -describe 'Recovery::LifeCycle' do +describe 'Dossier::Recovery::LifeCycle' do describe '.load_export_destroy_and_import' do let(:procedure) do create(:procedure, diff --git a/spec/lib/recovery/revision_life_cycle_spec.rb b/spec/lib/recovery/revision_life_cycle_spec.rb new file mode 100644 index 000000000..4ea60b5b4 --- /dev/null +++ b/spec/lib/recovery/revision_life_cycle_spec.rb @@ -0,0 +1,52 @@ +describe 'Recovery::Revision::LifeCycle' do + describe '.load_export_destroy_and_import' do + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :yes_no, libelle: 'YES!!!' }, {}]) } + let(:dossier) { create(:dossier, :with_populated_champs, procedure:) } + let(:yes_no_type_de_champ) { procedure.published_revision.types_de_champ.first } + let(:file_path) { Rails.root.join('spec', 'fixtures', 'revision_export.dump') } + let(:exporter) { Recovery::RevisionExporter.new(revision_ids: [procedure.published_revision.id], file_path:) } + let(:importer) { Recovery::RevisionImporter.new(file_path:) } + + def cleanup_export_file + file_path.delete if file_path.exist? + end + + before do + cleanup_export_file + procedure.publish! + exporter.dump + end + + after { cleanup_export_file } + + context "when type de champ missing" do + before do + dossier + procedure.published_revision.remove_type_de_champ(yes_no_type_de_champ.stable_id) + end + + it do + expect { DossierPreloader.load_one(dossier) }.to raise_error(ArgumentError) + expect(dossier.champs_public.size).to eq(1) + expect(dossier.champs.size).to eq(2) + importer.load + expect { DossierPreloader.load_one(dossier) }.not_to raise_error(ArgumentError) + expect(dossier.champs_public.size).to eq(2) + end + end + + context "when type de champ libelle updated" do + before do + dossier + yes_no_type_de_champ.update!(libelle: 'new libelle') + end + + it do + expect(yes_no_type_de_champ.libelle).to eq('new libelle') + importer.load + yes_no_type_de_champ.reload + expect(yes_no_type_de_champ.libelle).to eq('YES!!!') + end + end + end +end