diff --git a/app/models/etd.rb b/app/models/etd.rb index 7f0ab1245..d59cc3fab 100644 --- a/app/models/etd.rb +++ b/app/models/etd.rb @@ -1,6 +1,5 @@ require 'workflow_setup' -# Generated via -# `rails generate hyrax:work Etd` + class Etd < ActiveFedora::Base include ::ProquestBehaviors include ::Hyrax::WorkBehavior @@ -16,6 +15,24 @@ class Etd < ActiveFedora::Base after_initialize :set_defaults, unless: :persisted? before_save :set_research_field_ids, :index_committee_chair_name, :index_committee_members_names + ## + # @!attribute [rw] visibility_translator_class + # @return [VisibilityTranslatorClass] + attr_writer :visibility_translator_class + + def visibility_translator_class + @visibility_translator_class ||= VisibilityTranslator + end + + ## + # @return [VisibilityTranslator] + def visibility_translator + visibility_translator_class.new(obj: self) + end + + delegate :visibility, to: :visibility_translator + delegate :visibility=, to: :visibility_translator + # Get all attached file sets that are "primary" def primary_file_fs members.select(&:primary?) diff --git a/app/services/visibility_translator.rb b/app/services/visibility_translator.rb index 2457ae0af..b7bd0c042 100644 --- a/app/services/visibility_translator.rb +++ b/app/services/visibility_translator.rb @@ -20,6 +20,7 @@ class VisibilityTranslator ALL_EMBARGOED = 'embargo; all'.freeze FILES_EMBARGOED = 'embargo; file'.freeze TOC_EMBARGOED = 'embargo; toc + file'.freeze + OPEN = Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC attr_accessor :obj @@ -32,13 +33,60 @@ def self.visibility(obj:) end def visibility - return VisibilityProxy.new(obj).visibility unless obj.under_embargo? - return ALL_EMBARGOED if obj.abstract_embargoed - return TOC_EMBARGOED if obj.toc_embargoed + return proxy.visibility unless obj.under_embargo? + return ALL_EMBARGOED if obj.abstract_embargoed + return TOC_EMBARGOED if obj.toc_embargoed FILES_EMBARGOED end + def visibility=(value) + case value + when FILES_EMBARGOED + raise(InvalidVisibilityError.new('Invalid embargo visibility level:', value, obj)) unless + obj.under_embargo? + + obj.files_embargoed = true + obj.toc_embargoed = false + obj.abstract_embargoed = false + proxy.visibility = OPEN + when TOC_EMBARGOED + raise(InvalidVisibilityError.new('Invalid embargo visibility level:', value, obj)) unless + obj.under_embargo? + + obj.files_embargoed = true + obj.toc_embargoed = true + obj.abstract_embargoed = false + proxy.visibility = OPEN + when ALL_EMBARGOED + raise(InvalidVisibilityError.new('Invalid embargo visibility level:', value, obj)) unless + obj.under_embargo? + + obj.files_embargoed = true + obj.toc_embargoed = true + obj.abstract_embargoed = true + proxy.visibility = OPEN + else + proxy.visibility = value + end + end + + def proxy + VisibilityProxy.new(obj) + end + + class InvalidVisibilityError < ArgumentError + def initialize(msg = 'Invalid visibility level:', level = nil, obj = nil) + @level = level + @obj = obj + @msg = msg + " #{level}\nNo embargo is set on #{obj ? obj.id : 'the object'}." + end + + def message + @msg + end + end + ## # Determines the value of the default `#visibility` method as implemented in # `Hydra::AccessControls::Visibility` for the provided `source`. Since we @@ -57,6 +105,7 @@ class VisibilityProxy include Hydra::AccessControls::Visibility def_delegator :@original, :read_groups + def_delegator :@original, :set_read_groups def initialize(original) @original = original diff --git a/spec/models/etd_spec.rb b/spec/models/etd_spec.rb index 4c05b7f98..528c7c1fd 100644 --- a/spec/models/etd_spec.rb +++ b/spec/models/etd_spec.rb @@ -431,4 +431,110 @@ its(:degree_granting_institution) { is_expected.to eq "http://id.loc.gov/vocabulary/organizations/geu" } end end + + describe '#visibility' do + subject(:etd) { described_class.new } + + let(:all) { VisibilityTranslator::ALL_EMBARGOED } + let(:files) { VisibilityTranslator::FILES_EMBARGOED } + let(:open) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC } + let(:restricted) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE } + let(:toc) { VisibilityTranslator::TOC_EMBARGOED } + + it 'is restricted by default' do + expect(etd.visibility).to eq restricted + end + + context 'when under full embargo' do + subject(:etd) { FactoryBot.create(:sample_data_with_everything_embargoed) } + + it 'is embargo (all)' do + expect(etd.visibility).to eq all + end + end + + context 'when under file-only embargo' do + subject(:etd) { FactoryBot.create(:sample_data_with_only_files_embargoed) } + + it 'is embargo (file)' do + expect(etd.visibility).to eq files + end + end + + context 'when under toc embargo' do + subject(:etd) do + FactoryBot.create(:sample_data_with_only_files_embargoed, toc_embargoed: true) + end + + it 'is embargo (toc + file)' do + expect(etd.visibility).to eq toc + end + end + + context 'when restricted' do + subject(:etd) { FactoryBot.create(:etd, visibility: restricted) } + + it 'is restricted' do + expect(etd.visibility).to eq restricted + end + end + end + + describe '#visibility=' do + subject(:etd) { FactoryBot.create(:etd, visibility: restricted) } + + let(:all) { VisibilityTranslator::ALL_EMBARGOED } + let(:files) { VisibilityTranslator::FILES_EMBARGOED } + let(:open) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC } + let(:restricted) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE } + let(:toc) { VisibilityTranslator::TOC_EMBARGOED } + + it 'can set to open' do + expect { etd.visibility = open } + .to change { etd.visibility } + .to open + end + + context 'with no embargo set' do + it 'cannot set to file restricted access' do + expect { etd.visibility = files }.to raise_error ArgumentError + end + + it 'cannot set to toc restricted access' do + expect { etd.visibility = toc }.to raise_error ArgumentError + end + + it 'cannot set to all restricted access' do + expect { etd.visibility = all }.to raise_error ArgumentError + end + end + + context 'with an embargo' do + subject(:etd) do + FactoryBot.create(:tomorrow_expiration, + files_embargoed: false, + toc_embargoed: false) + end + + it 'can set to file restricted access' do + expect { etd.visibility = files } + .to change { etd.visibility } + .to files + end + + it 'can set to toc restricted access' do + expect { etd.visibility = toc } + .to change { etd.visibility } + .to toc + end + + it 'can set to all restricted access' do + etd.visibility = files + + expect { etd.visibility = all } + .to change { etd.visibility } + .to all + end + end + end end diff --git a/spec/services/embargo_expiration_service_spec.rb b/spec/services/embargo_expiration_service_spec.rb index 19fed47d8..6bf7576ce 100644 --- a/spec/services/embargo_expiration_service_spec.rb +++ b/spec/services/embargo_expiration_service_spec.rb @@ -98,7 +98,7 @@ it "changes the embargo permissions" do expect { service.expire_embargoes } .to change { etd.reload.visibility } - .from(etd.visibility_during_embargo) + .from(etd.visibility) .to(etd.visibility_after_embargo) end @@ -108,7 +108,7 @@ it 'does not deactivate embargo' do expect { service.expire_embargoes } .not_to change { etd.visibility } - .from(etd.visibility_during_embargo) + .from(etd.visibility) expect(etd.under_embargo?).to be_truthy end diff --git a/spec/services/visibility_translator_spec.rb b/spec/services/visibility_translator_spec.rb index f12f08ce1..006fb8939 100644 --- a/spec/services/visibility_translator_spec.rb +++ b/spec/services/visibility_translator_spec.rb @@ -55,4 +55,59 @@ end end end + + describe '#visibility=' do + let(:obj) { FactoryBot.create(:etd, visibility: restricted) } + + it 'can set visibility of object to open' do + expect { translator.visibility = open } + .to change { obj.visibility } + .to open + end + + context 'when the work has no embargo' do + it 'cannot set visibility of object to file restricted level' do + expect { translator.visibility = described_class::FILES_EMBARGOED } + .to raise_error ArgumentError + end + + it 'cannot set visibility of object to toc restricted level' do + expect { translator.visibility = described_class::TOC_EMBARGOED } + .to raise_error ArgumentError + end + + it 'cannot set visibility of object to all restricted level' do + expect { translator.visibility = described_class::ALL_EMBARGOED } + .to raise_error ArgumentError + end + end + + context 'when the work is under embargo' do + let(:obj) do + FactoryBot.create(:tomorrow_expiration, + files_embargoed: false, + toc_embargoed: false) + end + + it 'can set visibility of object to file restricted level' do + expect { translator.visibility = described_class::FILES_EMBARGOED } + .to change { obj.visibility } + .to described_class::FILES_EMBARGOED + end + + it 'can set visibility of object to toc restricted level' do + expect { translator.visibility = described_class::TOC_EMBARGOED } + .to change { obj.visibility } + .to described_class::TOC_EMBARGOED + end + + it 'can set visibility of object to all restricted level' do + translator.visibility = described_class::FILES_EMBARGOED + + expect { translator.visibility = described_class::ALL_EMBARGOED } + .to change { obj.visibility } + .to described_class::ALL_EMBARGOED + end + end + end end