diff --git a/app/services/constituent_service.rb b/app/services/constituent_service.rb index 00deba1ee2..7f656a7f8d 100644 --- a/app/services/constituent_service.rb +++ b/app/services/constituent_service.rb @@ -16,7 +16,7 @@ def initialize(parent_druid:) # subsequent calls will erase the previous changes. # @param [Array] child_druids the identifiers of the child objects def add(child_druids:) - ResetContentMetadataService.new(druid: parent_druid).reset + ResetContentMetadataService.new(druid: parent_druid).reset if parent # ensures parent is combinable child_druids.each do |child_druid| add_constituent(child_druid: child_druid) @@ -29,7 +29,7 @@ def add(child_druids:) attr_reader :parent_druid def add_constituent(child_druid:) - child = ItemQueryService.find_modifiable_item(child_druid) + child = ItemQueryService.find_combinable_item(child_druid) child.contentMetadata.ng_xml.search('//resource').each do |resource| parent.contentMetadata.add_virtual_resource(child.id, resource) end @@ -38,6 +38,6 @@ def add_constituent(child_druid:) end def parent - @parent ||= ItemQueryService.find_modifiable_item(parent_druid) + @parent ||= ItemQueryService.find_combinable_item(parent_druid) end end diff --git a/app/services/item_query_service.rb b/app/services/item_query_service.rb index e4b4f64dfb..45bfabfea8 100644 --- a/app/services/item_query_service.rb +++ b/app/services/item_query_service.rb @@ -11,6 +11,16 @@ def initialize(id:, item_relation: default_item_relation) delegate :allows_modification?, to: :item + # @raises [RuntimeError] if the item is not modifiable + def self.find_combinable_item(druid) + query_service = ItemQueryService.new(id: druid) + query_service.item do |item| + raise "Item #{item.pid} is not open for modification" unless query_service.allows_modification? + raise "Item #{item.pid} is dark" if item.rightsMetadata.dra_object.dark? + raise "Item #{item.pid} is citation_only" if item.rightsMetadata.dra_object.citation_only? + end + end + # @raises [RuntimeError] if the item is not modifiable def self.find_modifiable_item(druid) query_service = ItemQueryService.new(id: druid) diff --git a/spec/services/constituent_service_spec.rb b/spec/services/constituent_service_spec.rb index 6940eec082..1cedc398fd 100644 --- a/spec/services/constituent_service_spec.rb +++ b/spec/services/constituent_service_spec.rb @@ -59,9 +59,10 @@ # Used in ContentMetadataDS#add_virtual_resource allow(parent.contentMetadata).to receive(:pid).and_return('druid:parent1') + allow(ItemQueryService).to receive(:find_combinable_item).with('druid:parent1').and_return(parent) allow(ItemQueryService).to receive(:find_modifiable_item).with('druid:parent1').and_return(parent) - allow(ItemQueryService).to receive(:find_modifiable_item).with('druid:child1').and_return(child1) - allow(ItemQueryService).to receive(:find_modifiable_item).with('druid:child2').and_return(child2) + allow(ItemQueryService).to receive(:find_combinable_item).with('druid:child1').and_return(child1) + allow(ItemQueryService).to receive(:find_combinable_item).with('druid:child2').and_return(child2) allow(Dor::Services::Client).to receive(:object).and_return(client) end @@ -88,9 +89,9 @@ end end - context 'when the parent is closed for modification' do + context 'when the parent is not combinable' do before do - allow(ItemQueryService).to receive(:find_modifiable_item).with(parent.id).and_raise('nope') + allow(ItemQueryService).to receive(:find_combinable_item).with(parent.id).and_raise('nope') end it 'merges nothing' do @@ -100,9 +101,9 @@ end end - context 'when the child is closed for modification' do + context 'when a child is not combinable' do before do - allow(ItemQueryService).to receive(:find_modifiable_item).with(child2.id).and_raise('not modifiable') + allow(ItemQueryService).to receive(:find_combinable_item).with(child2.id).and_raise('not modifiable') end it 'merges all the chidren before an error is encountered' do diff --git a/spec/services/item_query_service_spec.rb b/spec/services/item_query_service_spec.rb new file mode 100644 index 0000000000..c54b7cf335 --- /dev/null +++ b/spec/services/item_query_service_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ItemQueryService do + subject(:service) { described_class } + + let(:druid) { 'ab123cd4567' } + let(:item) { instantiate_fixture('druid:ab123cd4567', Dor::Item) } + + before do + allow(Dor::Item).to receive(:find).and_return(item) + end + + describe '.find_combinable_item' do + it 'raises error if object does not allow modification' do + allow(item).to receive(:allows_modification?).and_return(false) + expect { service.find_combinable_item('ab123cd4567') }.to raise_error(RuntimeError, 'Item druid:ab123cd4567 is not open for modification') + end + it 'raises error if object is dark' do + dra = instance_double(Dor::RightsAuth, dark?: true, citation_only?: false) + rights_ds = instance_double(Dor::RightsMetadataDS, dra_object: dra) + allow(item).to receive(:rightsMetadata).and_return(rights_ds) + allow(item).to receive(:allows_modification?).and_return(true) + expect { service.find_combinable_item('ab123cd4567') }.to raise_error(RuntimeError, 'Item druid:ab123cd4567 is dark') + end + it 'raises error if object is citation_only' do + dra = instance_double(Dor::RightsAuth, dark?: false, citation_only?: true) + rights_ds = instance_double(Dor::RightsMetadataDS, dra_object: dra) + allow(item).to receive(:rightsMetadata).and_return(rights_ds) + allow(item).to receive(:allows_modification?).and_return(true) + expect { service.find_combinable_item('ab123cd4567') }.to raise_error(RuntimeError, 'Item druid:ab123cd4567 is citation_only') + end + it 'returns item otherwise' do + dra = instance_double(Dor::RightsAuth, dark?: false, citation_only?: false) + rights_ds = instance_double(Dor::RightsMetadataDS, dra_object: dra) + allow(item).to receive(:rightsMetadata).and_return(rights_ds) + allow(item).to receive(:allows_modification?).and_return(true) + service.find_combinable_item('ab123cd4567') + end + end + + describe '.find_modifiable_item' do + it 'raises error if object does not allow modification' do + allow(item).to receive(:allows_modification?).and_return(false) + expect { service.find_modifiable_item('ab123cd4567') }.to raise_error(RuntimeError, 'Item druid:ab123cd4567 is not open for modification') + end + it 'returns item if it is modifiable' do + allow(item).to receive(:allows_modification?).and_return(true) + service.find_modifiable_item('ab123cd4567') + end + end +end