Skip to content

Commit

Permalink
Use VisibilityTranslator to determine and set Etd#visibility
Browse files Browse the repository at this point in the history
Adds three new visibility levels to `Etd`. These are usable when an embargo is
set.

First we add delegation to a settable `#visibility_translator` (defaulting to an
instance of `VisibilityTranslator`). This allows the `Etd` to infer its
embargoed `#visibility` level based on the existing `*_embargoed` flags. We then
add logic to `VisibilityTranslator` for setting visibility to the three new
levels _iff_ an embargo is set on the object.

Future work will shift existing clients to using the visibility setters, instead
of setting `*_embargoed` flags manually and add the new visibility levels to the
embargo edit pages. We may also want to consider replacing the `*_embargoed`
flags with data on the `Embargo` ActiveRecord objects.

We shift expectations of some tests since `Etd#visibility_during_embargo`
currently does not reflect the actual work visibility during the embargo.
See: #1477.

Connected to #1206.
  • Loading branch information
Tom Johnson committed Aug 3, 2018
1 parent ac39e3f commit ecba0f2
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 7 deletions.
21 changes: 19 additions & 2 deletions app/models/etd.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require 'workflow_setup'
# Generated via
# `rails generate hyrax:work Etd`

class Etd < ActiveFedora::Base
include ::ProquestBehaviors
include ::Hyrax::WorkBehavior
Expand All @@ -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?)
Expand Down
55 changes: 52 additions & 3 deletions app/services/visibility_translator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down
106 changes: 106 additions & 0 deletions spec/models/etd_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions spec/services/embargo_expiration_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
55 changes: 55 additions & 0 deletions spec/services/visibility_translator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit ecba0f2

Please sign in to comment.