From 805be79bc7f4dc74e622179e8018989c7ee69a5c Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Mon, 5 Jun 2023 16:27:05 -0500 Subject: [PATCH 1/7] Adds batch process to pull children from preservica for existing parent --- app/models/batch_process.rb | 16 +- app/models/parent_object.rb | 27 ++- .../templates/reingest_with_preservica.csv | 1 + .../csv/preservica/preservica_reingest.csv | 2 + .../preservica_reingest_invalid.csv | 2 + ...reservica_reingest_existing_parent_spec.rb | 156 ++++++++++++++++++ 6 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 public/batch_processes/templates/reingest_with_preservica.csv create mode 100644 spec/fixtures/csv/preservica/preservica_reingest.csv create mode 100644 spec/fixtures/csv/preservica/preservica_reingest_invalid.csv create mode 100644 spec/models/preservica/preservica_reingest_existing_parent_spec.rb diff --git a/app/models/batch_process.rb b/app/models/batch_process.rb index 2ac45f59d..2afbfa560 100644 --- a/app/models/batch_process.rb +++ b/app/models/batch_process.rb @@ -26,7 +26,7 @@ class BatchProcess < ApplicationRecord # rubocop:disable Metrics/ClassLength # LISTS AVAILABLE BATCH ACTIONS # rubocop:disable Metrics/LineLength def self.batch_actions - ['create parent objects', 'update parent objects', 'update child objects caption and label', 'delete parent objects', 'delete child objects', 'export all parent objects by admin set', 'export parent metadata', 'export child oids', 'reassociate child oids', 'recreate child oid ptiffs', 'update fulltext status', 'resync with preservica'] + ['create parent objects', 'update parent objects', 'update child objects caption and label', 'delete parent objects', 'delete child objects', 'export all parent objects by admin set', 'export parent metadata', 'export child oids', 'reassociate child oids', 'recreate child oid ptiffs', 'update fulltext status', 'reingest with preservica', 'resync with preservica'] end # rubocop:enable Metrics/LineLength @@ -172,6 +172,8 @@ def determine_background_jobs RecreateChildOidPtiffsJob.perform_later(self) when 'update fulltext status' UpdateFulltextStatusJob.perform_later(self) + when 'reingest with preservica' + SyncFromPreservicaJob.perform_later(self) when 'resync with preservica' SyncFromPreservicaJob.perform_later(self) end @@ -479,6 +481,7 @@ def sync_from_preservica batch_processing_event("Parent OID: #{row['oid']} not found in database", 'Skipped Import') if parent_object.nil? next end + update_parent_during_reingest(parent_object) next unless validate_preservica_sync(parent_object, row) local_children_hash = {} parent_object.child_objects.each do |local_co| @@ -512,11 +515,20 @@ def sync_from_preservica # rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/AbcSize + # UPDATE PARENT OBJECT IF REINGEST + def update_parent_during_reingest(parent_object) + return unless batch_action == 'reingest with preservica' + parent_object.digital_object_source = row['digital_object_source'] + parent_object.preservica_uri = row['preservica_uri'] + parent_object.preservica_representation_type = row['preservica_representation_type'] + parent_object.save! + end + # SYNC IMAGES FROM PRESERVICA def sync_images_preservica(local_children_hash, preservica_children_hash, parent_object) if local_children_hash != preservica_children_hash setup_for_background_jobs(parent_object, parent_object.source_name) - parent_object.sync_from_preservica(local_children_hash, preservica_children_hash) + parent_object.sync_from_preservica(local_children_hash, preservica_children_hash, batch_action) else batch_processing_event("Child object count and order is the same. No update needed.", "Skipped Row") end diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index 7f11a1a57..757c97aa8 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -221,21 +221,18 @@ def upsert_preservica_ingest_child_objects(preservica_ingest_hash) PreservicaIngest.insert_all(preservica_ingest_hash) end - def sync_from_preservica(_local_children_hash, preservica_children_hash) - # iterate through local hashes and remove any children no longer found on preservica - child_objects.each do |co| - co.destroy unless found_in_preservica(co.preservica_content_object_uri, preservica_children_hash) - end + def sync_from_preservica(_local_children_hash, preservica_children_hash, batch_action) + clean_from_preservica_sync(batch_action, preservica_children_hash) # iterate through preservica and update when local version found preservica_children_hash.each_value do |value| - co = ChildObject.find_by(parent_object_oid: oid, preservica_content_object_uri: value[:content_uri]) + co = find_child_for_sync(batch_action) next if co.nil? co.pyramidal_tiff.force_update = true co.order = value[:order] co.preservica_content_object_uri = value[:content_uri] co.preservica_generation_uri = value[:generation_uri] co.preservica_bitstream_uri = value[:bitstream_uri] - co.sha512_checksum = value[:sha512_checksum] + co.sha512_checksum = value[:checksum] co.last_preservica_update = Time.current replace_preservica_tif(co) co.save! @@ -245,12 +242,28 @@ def sync_from_preservica(_local_children_hash, preservica_children_hash) create_child_records end + def clean_from_preservica_sync(batch_action, preservica_children_hash) + return unless batch_action == 'sync with preservica' + # iterate through local hashes and remove any children no longer found on preservica + child_objects.each do |co| + co.destroy unless found_in_preservica(co.preservica_content_object_uri, preservica_children_hash) + end + end + def found_in_preservica(local_preservica_content_object_uri, preservica_children_hash) preservica_children_hash.any? do |_, value| value[:content_uri] == local_preservica_content_object_uri end end + def find_child_for_sync(batch_action) + if batch_action == 'sync with preservica' + ChildObject.find_by(parent_object_oid: oid, preservica_content_object_uri: value[:content_uri]) + else # reingest + ChildObject.find_by(parent_object_oid: oid, order: value[:order]) + end + end + def replace_preservica_tif(co) PreservicaImageService.new(preservica_uri, admin_set.key).image_list(preservica_representation_type).map do |child_hash| preservica_copy_to_access(child_hash, co.oid) diff --git a/public/batch_processes/templates/reingest_with_preservica.csv b/public/batch_processes/templates/reingest_with_preservica.csv new file mode 100644 index 000000000..d78ae916d --- /dev/null +++ b/public/batch_processes/templates/reingest_with_preservica.csv @@ -0,0 +1 @@ +oid,digital_object_source,preservica_uri,preservica_representation_type \ No newline at end of file diff --git a/spec/fixtures/csv/preservica/preservica_reingest.csv b/spec/fixtures/csv/preservica/preservica_reingest.csv new file mode 100644 index 000000000..987a074b4 --- /dev/null +++ b/spec/fixtures/csv/preservica/preservica_reingest.csv @@ -0,0 +1,2 @@ +oid,digital_object_source,preservica_uri,preservica_representation_type +200000000,Preservica,/preservica/api/entity/structural-objects/7fe35e8c-c21a-444a-a2e2-e3c926b519c5,Preservation \ No newline at end of file diff --git a/spec/fixtures/csv/preservica/preservica_reingest_invalid.csv b/spec/fixtures/csv/preservica/preservica_reingest_invalid.csv new file mode 100644 index 000000000..1b28e28a1 --- /dev/null +++ b/spec/fixtures/csv/preservica/preservica_reingest_invalid.csv @@ -0,0 +1,2 @@ +oid,digital_object_source,preservica_uri,preservica_representation_type +12345,Preservica,/preservica/api/entity/structural-objects/7fe35e8c-c21a-444a-a2e2-e3c926b519c5,Preservation \ No newline at end of file diff --git a/spec/models/preservica/preservica_reingest_existing_parent_spec.rb b/spec/models/preservica/preservica_reingest_existing_parent_spec.rb new file mode 100644 index 000000000..38dfe3ee1 --- /dev/null +++ b/spec/models/preservica/preservica_reingest_existing_parent_spec.rb @@ -0,0 +1,156 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Preservica::PreservicaObject, type: :model, prep_metadata_sources: true, prep_admin_sets: true do + subject(:batch_process) { BatchProcess.new } + let(:admin_set) { FactoryBot.create(:admin_set, key: 'brbl') } + let(:admin_set_sml) { FactoryBot.create(:admin_set, key: 'sml') } + let(:user) { FactoryBot.create(:user, uid: "mk2525") } + let(:aspace_parent) { FactoryBot.create(:parent_object, oid: 200_000_000, admin_set: AdminSet.find_by_key('brbl')) } + let(:co_1) { FactoryBot.create(:child_object, oid: 1_002_533, parent_object: aspace_parent, order: 1, label: 'original label', caption: 'original caption') } + let(:co_2) { FactoryBot.create(:child_object, oid: 1_002_534, parent_object: aspace_parent, order: 2, label: 'original label', caption: 'original caption') } + let(:co_3) { FactoryBot.create(:child_object, oid: 1_002_535, parent_object: aspace_parent, order: 3, label: 'original label', caption: 'original caption') } + let(:ptf_1) { PyramidalTiff.new(co_1) } + let(:ptf_2) { PyramidalTiff.new(co_2) } + let(:ptf_3) { PyramidalTiff.new(co_3) } + let(:preservica_reingest_invalid) { Rack::Test::UploadedFile.new(Rails.root.join(fixture_path, "csv", "preservica", "preservica_reingest_invalid.csv")) } + let(:preservica_reingest) { Rack::Test::UploadedFile.new(Rails.root.join(fixture_path, "csv", "preservica", "preservica_reingest.csv")) } + + around do |example| + preservica_host = ENV['PRESERVICA_HOST'] + preservica_creds = ENV['PRESERVICA_CREDENTIALS'] + ENV['PRESERVICA_HOST'] = "testpreservica" + ENV['PRESERVICA_CREDENTIALS'] = '{"brbl": {"username":"xxxxx", "password":"xxxxx"}}' + access_host = ENV['ACCESS_MASTER_MOUNT'] + ENV['ACCESS_MASTER_MOUNT'] = File.join("spec", "fixtures", "images", "access_masters") + perform_enqueued_jobs do + example.run + end + ENV['PRESERVICA_HOST'] = preservica_host + ENV['PRESERVICA_CREDENTIALS'] = preservica_creds + ENV['ACCESS_MASTER_MOUNT'] = access_host + end + + before do + login_as(:user) + batch_process.user_id = user.id + stub_pdfs + aspace_parent + co_1 + co_2 + co_3 + stub_preservica_login + fixtures = %w[preservica/api/entity/structural-objects/7fe35e8c-c21a-444a-a2e2-e3c926b519c5/children + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3r/representations + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3r/representations/Access + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3r/representations/Preservation + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b486/generations + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b486/generations/1 + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b486/generations/1/bitstreams/1 + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3d/representations + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3d/representations/Access + preservica/api/entity/information-objects/1e42a2bb-8953-41b6-bcc3-1a19c86a5e3d/representations/Preservation + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b489/generations + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b489/generations/1 + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b489/generations/1/bitstreams/1 + preservica/api/entity/information-objects/f44ba97e-af2b-498e-b118-ed1247822f44/representations + preservica/api/entity/information-objects/f44ba97e-af2b-498e-b118-ed1247822f44/representations/Access + preservica/api/entity/information-objects/f44ba97e-af2b-498e-b118-ed1247822f44/representations/Preservation + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b487/generations + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b487/generations/1 + preservica/api/entity/content-objects/ae328d84-e429-4d46-a865-9ee11157b487/generations/1/bitstreams/1] + + fixtures.each do |fixture| + stub_request(:get, "https://test#{fixture}").to_return( + status: 200, body: File.open(File.join(fixture_path, "#{fixture}.xml")) + ) + end + stub_preservica_tifs_set_of_three + stub_request(:get, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002533.tif") + .to_return(status: 200, body: File.open('spec/fixtures/images/sample.tiff', 'rb')) + stub_request(:head, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002533.tif") + .to_return(status: 200) + stub_request(:put, "https://yale-test-image-samples.s3.amazonaws.com/ptiffs/33/10/02/53/1002533.tif") + .to_return(status: 200) + stub_request(:get, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002534.tif") + .to_return(status: 200, body: File.open('spec/fixtures/images/sample.tiff', 'rb')) + stub_request(:head, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002534.tif") + .to_return(status: 200) + stub_request(:put, "https://yale-test-image-samples.s3.amazonaws.com/ptiffs/34/10/02/53/1002534.tif") + .to_return(status: 200) + stub_request(:get, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002535.tif") + .to_return(status: 200, body: File.open('spec/fixtures/images/sample.tiff', 'rb')) + stub_request(:head, "https://yale-test-image-samples.s3.amazonaws.com/originals/1002535.tif") + .to_return(status: 200) + stub_request(:put, "https://yale-test-image-samples.s3.amazonaws.com/ptiffs/03/35/10/02/53/1002535.tif") + .to_return(status: 200) + end + + context 'user with permission' do + before do + user.add_role(:editor, admin_set) + login_as(:user) + end + + it 'can reingest child objects and keep oids, captions and labels but replace images' do + File.delete("spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif") if File.exist?("spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif") + File.delete("spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif") if File.exist?("spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif") + File.delete("spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif") if File.exist?("spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif") + allow(S3Service).to receive(:s3_exists?).and_return(false) + expect(ParentObject.count).to eq 1 + expect(ChildObject.count).to eq 3 + po_first = ParentObject.first + co_first = ChildObject.first + expect(co_first.oid).to eq 1_002_533 + expect(co_first.caption).to eq 'original caption' + expect(co_first.label).to eq 'original label' + expect(co_first.sha512_checksum).to be nil + expect(po_first.last_preservica_update).to be nil + expect(ptf_1.access_master_path).to eq "spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif" + expect(ptf_2.access_master_path).to eq "spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif" + expect(ptf_3.access_master_path).to eq "spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif" + + reingest_batch_process = BatchProcess.new(batch_action: 'reingest with preservica', user: user) + expect do + reingest_batch_process.file = preservica_reingest + reingest_batch_process.save! + end.not_to change { ChildObject.count } + po_first = ParentObject.first + co_first = ChildObject.first + + expect(po_first.last_preservica_update).not_to be nil + expect(co_first.sha512_checksum).not_to be nil + expect(co_first.oid).to eq 1_002_533 + expect(co_first.caption).to eq 'original caption' + expect(co_first.label).to eq 'original label' + expect(File.exist?("spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif")).to be true + expect(File.exist?("spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif")).to be true + expect(File.exist?("spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif")).to be true + File.delete("spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif") if File.exist?("spec/fixtures/images/access_masters/03/33/10/02/53/1002533.tif") + File.delete("spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif") if File.exist?("spec/fixtures/images/access_masters/03/34/10/02/53/1002534.tif") + File.delete("spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif") if File.exist?("spec/fixtures/images/access_masters/03/35/10/02/53/1002535.tif") + end + end + + context 'user without permission' do + before do + user.remove_role(:editor) + login_as(:user) + end + + it 'can throw an error if user does not have permission on parent object' do + allow(S3Service).to receive(:s3_exists?).and_return(false) + parent_object = ParentObject.new(oid: 12_345, admin_set: AdminSet.find_by_key('brbl')) + parent_object.save + + reingest_batch_process = BatchProcess.new(batch_action: 'reingest with preservica', user: user) + expect do + reingest_batch_process.file = preservica_reingest_invalid + reingest_batch_process.save! + end.not_to change { ChildObject.count } + expect(reingest_batch_process.batch_ingest_events_count).to be 1 + expect(reingest_batch_process.batch_ingest_events.last.reason).to eq('Skipping row with parent oid: 12345, user does not have permission to update') + end + end +end From 6f2929a8d7e9859abfac8d93537cbd5b5562595f Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Tue, 6 Jun 2023 10:10:33 -0500 Subject: [PATCH 2/7] Pass value as param --- app/models/parent_object.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index 757c97aa8..32f38e8a8 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -225,7 +225,7 @@ def sync_from_preservica(_local_children_hash, preservica_children_hash, batch_a clean_from_preservica_sync(batch_action, preservica_children_hash) # iterate through preservica and update when local version found preservica_children_hash.each_value do |value| - co = find_child_for_sync(batch_action) + co = find_child_for_sync(batch_action, value) next if co.nil? co.pyramidal_tiff.force_update = true co.order = value[:order] @@ -256,11 +256,11 @@ def found_in_preservica(local_preservica_content_object_uri, preservica_children end end - def find_child_for_sync(batch_action) - if batch_action == 'sync with preservica' - ChildObject.find_by(parent_object_oid: oid, preservica_content_object_uri: value[:content_uri]) - else # reingest + def find_child_for_sync(batch_action, value) + if batch_action == 'reingest with preservica' ChildObject.find_by(parent_object_oid: oid, order: value[:order]) + else # sync + ChildObject.find_by(parent_object_oid: oid, preservica_content_object_uri: value[:content_uri]) end end From d311ff4044dc15f71e39b37377fa71ee98d5b346 Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Tue, 6 Jun 2023 10:35:41 -0500 Subject: [PATCH 3/7] Fix typos --- app/models/batch_process.rb | 4 ++-- app/models/parent_object.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/batch_process.rb b/app/models/batch_process.rb index 2afbfa560..575fc7992 100644 --- a/app/models/batch_process.rb +++ b/app/models/batch_process.rb @@ -481,7 +481,7 @@ def sync_from_preservica batch_processing_event("Parent OID: #{row['oid']} not found in database", 'Skipped Import') if parent_object.nil? next end - update_parent_during_reingest(parent_object) + update_parent_during_reingest(parent_object, row) next unless validate_preservica_sync(parent_object, row) local_children_hash = {} parent_object.child_objects.each do |local_co| @@ -516,7 +516,7 @@ def sync_from_preservica # rubocop:enable Metrics/AbcSize # UPDATE PARENT OBJECT IF REINGEST - def update_parent_during_reingest(parent_object) + def update_parent_during_reingest(parent_object, row) return unless batch_action == 'reingest with preservica' parent_object.digital_object_source = row['digital_object_source'] parent_object.preservica_uri = row['preservica_uri'] diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index 32f38e8a8..e2a4c7ab1 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -243,7 +243,7 @@ def sync_from_preservica(_local_children_hash, preservica_children_hash, batch_a end def clean_from_preservica_sync(batch_action, preservica_children_hash) - return unless batch_action == 'sync with preservica' + return unless batch_action == 'resync with preservica' # iterate through local hashes and remove any children no longer found on preservica child_objects.each do |co| co.destroy unless found_in_preservica(co.preservica_content_object_uri, preservica_children_hash) From 9da78dc79bbfc8fb4ff6c3cdcf0d68ffd2ecb35e Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Wed, 7 Jun 2023 13:45:37 -0500 Subject: [PATCH 4/7] Add cleaning to reingest --- app/models/parent_object.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index e2a4c7ab1..3a0a9e48d 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -222,7 +222,7 @@ def upsert_preservica_ingest_child_objects(preservica_ingest_hash) end def sync_from_preservica(_local_children_hash, preservica_children_hash, batch_action) - clean_from_preservica_sync(batch_action, preservica_children_hash) + clean_resync(batch_action, preservica_children_hash) # iterate through preservica and update when local version found preservica_children_hash.each_value do |value| co = find_child_for_sync(batch_action, value) @@ -237,12 +237,12 @@ def sync_from_preservica(_local_children_hash, preservica_children_hash, batch_a replace_preservica_tif(co) co.save! end - + clean_reingest(batch_action) # create child records for any new items in preservica create_child_records end - def clean_from_preservica_sync(batch_action, preservica_children_hash) + def clean_resync(batch_action, preservica_children_hash) return unless batch_action == 'resync with preservica' # iterate through local hashes and remove any children no longer found on preservica child_objects.each do |co| @@ -270,6 +270,15 @@ def replace_preservica_tif(co) end end + def clean_reingest(batch_action) + return unless batch_action == 'reingest with preservica' + # use cos instead of child_objects here because data was not updating on parent object but was updated on child object + cos = ChildObject.where(parent_object_oid: oid) + cos.each do |co| + co.destroy if co.preservica_content_object_uri.nil? + end + end + def array_of_child_hashes_from_mets return unless current_batch_process&.mets_doc current_batch_process.mets_doc.combined.map { |child_hash| child_hash.select { |k| k != :thumbnail_flag && k != :child_uuid && k != :physical_id && k != :logical_id } } From 7d7639631d0b6b6ec2f7e0cb56bc2156713f7934 Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Mon, 28 Oct 2024 17:41:20 -0500 Subject: [PATCH 5/7] remove method --- app/models/parent_object.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index cb1f32f71..fcf1bc7db 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -284,14 +284,6 @@ def sync_from_preservica_update_all_ptiffs end end - def clean_resync(batch_action, preservica_children_hash) - return unless batch_action == 'resync with preservica' - # iterate through local hashes and remove any children no longer found on preservica - child_objects.each do |co| - co.destroy unless found_in_preservica(co.preservica_content_object_uri, preservica_children_hash) - end - end - def found_in_preservica(local_preservica_content_object_uri, preservica_children_hash) preservica_children_hash.any? do |_, value| value[:content_uri] == local_preservica_content_object_uri From b1ee8333c3baf448b35ee11698a66db5f3894a81 Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Mon, 28 Oct 2024 17:50:48 -0500 Subject: [PATCH 6/7] update find method --- app/models/parent_object.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/parent_object.rb b/app/models/parent_object.rb index fcf1bc7db..bd0a26746 100644 --- a/app/models/parent_object.rb +++ b/app/models/parent_object.rb @@ -256,7 +256,7 @@ def sync_from_preservica(_local_children_hash, preservica_children_hash) def sync_from_preservica_update_existing_children(preservica_children_hash) preservica_children_hash.each_value do |value| - co = find_child_for_sync(batch_action, value) + co = ChildObject.find_by(parent_object_oid: oid, preservica_content_object_uri: value[:content_uri]) next if co.nil? co.pyramidal_tiff.force_update = true co.order = value[:order] From 5138ccf0c8a7c832a023af1e0de00c9b8797b0dd Mon Sep 17 00:00:00 2001 From: K8Sewell Date: Tue, 29 Oct 2024 12:11:35 -0500 Subject: [PATCH 7/7] Update sync validation and error messages --- app/models/concerns/create_parent_object.rb | 12 +++++----- app/models/concerns/sync_from_preservica.rb | 22 ++++++++++--------- app/services/preservica_image_service.rb | 12 +++++++++- ...reservica_reingest_existing_parent_spec.rb | 2 ++ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/app/models/concerns/create_parent_object.rb b/app/models/concerns/create_parent_object.rb index e975cacd8..038c62925 100644 --- a/app/models/concerns/create_parent_object.rb +++ b/app/models/concerns/create_parent_object.rb @@ -23,13 +23,13 @@ def create_new_parent_csv batch_processing_event(e.message, e.kind) next rescue PreservicaImageService::PreservicaImageServiceError => e - if e.message.include?("bad URI") - batch_processing_event("The given URI does not match the URI of an entity in Preservica. Please make sure your URI is correct, starts with /structure-object/ or /information-object/, and includes no spaces or line breaks. ------------ Message from System: Skipping row [#{index + 2}] #{e.message}.", "Skipped Row") - elsif e.message.include?("entity.does.not.exist") - batch_processing_event("The given URI does not match the URI of an entity of this type in Preservica. Please make sure your Preservica URI and object structure type is correct. ------------ Message from System: Skipping row [#{index + 2}] #{e.message}.", "Skipped Row") - else + # if e.message.include?("bad URI") + # batch_processing_event("The given URI does not match the URI of an entity in Preservica. Please make sure your URI is correct, starts with /structure-object/ or /information-object/, and includes no spaces or line breaks. ------------ Message from System: Skipping row [#{index + 2}] #{e.message}.", "Skipped Row") + # elsif e.message.include?("entity.does.not.exist") + # batch_processing_event("The given URI does not match the URI of an entity of this type in Preservica. Please make sure your Preservica URI and object structure type is correct. ------------ Message from System: Skipping row [#{index + 2}] #{e.message}.", "Skipped Row") + # else batch_processing_event("Skipping row [#{index + 2}] #{e.message}.", "Skipped Row") - end + # end next end else diff --git a/app/models/concerns/sync_from_preservica.rb b/app/models/concerns/sync_from_preservica.rb index e5fe9e0eb..5dd7f1b4e 100644 --- a/app/models/concerns/sync_from_preservica.rb +++ b/app/models/concerns/sync_from_preservica.rb @@ -32,7 +32,8 @@ def sync_from_preservica end begin preservica_children_hash = {} - PreservicaImageService.new(parent_object.preservica_uri, parent_object.admin_set.key).image_list(parent_object.preservica_representation_type).each_with_index do |preservica_co, index| + parent_preservica_uri = parent_object.preservica_uri.presence || row['preservica_uri'].presence || + PreservicaImageService.new(parent_preservica_uri, parent_object.admin_set.key).image_list(parent_object.preservica_representation_type).each_with_index do |preservica_co, index| # increment by one so index lines up with order index_plus_one = index + 1 preservica_children_hash["hash_#{index_plus_one}".to_sym] = { order: index_plus_one, @@ -71,24 +72,25 @@ def sync_images_preservica(local_children_hash, preservica_children_hash, parent # rubocop:disable Metrics/MethodLength # ERROR HANDLING FOR PRESERVICA SYNC def validate_preservica_sync(parent_object, row) + # byebug if parent_object.redirect_to.present? batch_processing_event("Parent OID: #{row['oid']} is a redirected parent object", 'Skipped Import') false - elsif parent_object.preservica_uri.nil? - batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica URI", 'Skipped Import') + elsif !current_ability.can?(:update, parent_object) + batch_processing_event("Skipping row with parent oid: #{parent_object.oid}, user does not have permission to update", 'Permission Denied') + false + elsif parent_object.preservica_uri.nil? && row['preservica_uri'].nil? + batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica URI. Please ensure Preservica URI is saved to parent or included in CSV.", 'Skipped Import') false - elsif parent_object.digital_object_source != "Preservica" - batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica digital object source", 'Skipped Import') + elsif parent_object.digital_object_source != "Preservica" && row['digital_object_source'].nil? + batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica digital object source. Please ensure Digital Object Source is saved to parent or included in CSV.", 'Skipped Import') false - elsif parent_object.preservica_representation_type.nil? - batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica representation type", 'Skipped Import') + elsif parent_object.preservica_representation_type.nil? && row['preservica_representation_type'].nil? + batch_processing_event("Parent OID: #{row['oid']} does not have a Preservica representation type. Please ensure Preservica representation type is saved to parent or included in CSV.", 'Skipped Import') false elsif !parent_object.admin_set.preservica_credentials_verified batch_processing_event("Admin set #{parent_object.admin_set.key} does not have Preservica credentials set", 'Skipped Import') false - elsif !current_ability.can?(:update, parent_object) - batch_processing_event("Skipping row with parent oid: #{parent_object.oid}, user does not have permission to update", 'Permission Denied') - false else true end diff --git a/app/services/preservica_image_service.rb b/app/services/preservica_image_service.rb index 3c23c829a..ca5a808b8 100644 --- a/app/services/preservica_image_service.rb +++ b/app/services/preservica_image_service.rb @@ -3,11 +3,21 @@ class PreservicaImageService class PreservicaImageServiceError < StandardError attr_reader :id + # rubocop:disable Layout/LineLength def initialize(msg, id) @id = id - super("#{msg} for #{id}") + friendly_msg = if msg.include?("bad URI") + "The given URI does not match the URI of an entity in Preservica. Please make sure your URI is correct, starts with /structure-object/ or /information-object/, and includes no spaces or line breaks. ------------ Message from System: Skipping row [#{index + 2}] #{msg}." + elsif msg.include?("entity.does.not.exist") + "The given URI does not match the URI of an entity of this type in Preservica. Please make sure your Preservica URI and object structure type is correct. ------------ Message from System: Skipping row [#{index + 2}] #{msg}." + else + msg + end + + super("#{friendly_msg} for #{id}") end end + # rubocop:enable Layout/LineLength class PreservicaImageServiceNetworkError < PreservicaImageServiceError def initialize(msg, id) diff --git a/spec/models/preservica/preservica_reingest_existing_parent_spec.rb b/spec/models/preservica/preservica_reingest_existing_parent_spec.rb index 38dfe3ee1..b65622ac3 100644 --- a/spec/models/preservica/preservica_reingest_existing_parent_spec.rb +++ b/spec/models/preservica/preservica_reingest_existing_parent_spec.rb @@ -8,6 +8,7 @@ let(:admin_set_sml) { FactoryBot.create(:admin_set, key: 'sml') } let(:user) { FactoryBot.create(:user, uid: "mk2525") } let(:aspace_parent) { FactoryBot.create(:parent_object, oid: 200_000_000, admin_set: AdminSet.find_by_key('brbl')) } + # let(:sml_parent) { FactoryBot.create(:parent_object, oid: 12_345, admin_set: AdminSet.find_by_key('sml')) } let(:co_1) { FactoryBot.create(:child_object, oid: 1_002_533, parent_object: aspace_parent, order: 1, label: 'original label', caption: 'original caption') } let(:co_2) { FactoryBot.create(:child_object, oid: 1_002_534, parent_object: aspace_parent, order: 2, label: 'original label', caption: 'original caption') } let(:co_3) { FactoryBot.create(:child_object, oid: 1_002_535, parent_object: aspace_parent, order: 3, label: 'original label', caption: 'original caption') } @@ -140,6 +141,7 @@ end it 'can throw an error if user does not have permission on parent object' do + # byebug allow(S3Service).to receive(:s3_exists?).and_return(false) parent_object = ParentObject.new(oid: 12_345, admin_set: AdminSet.find_by_key('brbl')) parent_object.save