Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expand the EmbargoManager interface to handle releasing embargos #4305

Merged
merged 3 commits into from
May 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 108 additions & 4 deletions app/services/hyrax/embargo_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@ module Hyrax
# Provides utilities for managing the lifecycle of an `Hyrax::Embargo` on a
# `Hyrax::Resource`.
#
# This can do things like
# The embargo terminology used here is as follows:
#
# - "Release Date" is the day an embargo is scheduled to be released.
# - "Under Embargo" means the embargo is "active"; i.e. that its release
# date is today or later.
# - "Applied" means the embargo's pre-release visibility has been set on
# the resource.
# - "Released" means the embargo's post-release visibility has been set on
# the resource.
# - "Enforced" means the object's visibility matches the pre-release
# visibility of the embargo; i.e. the embargo has been applied,
# but not released.
#
# Note that an resource may be `#under_embargo?` even if the embargo is not
# be `#enforced?` (in this case, the application should seek to apply the
# embargo, e.g. via a scheduled job). Additionally, an embargo may be
# `#enforced?` after its release date (in this case, the application should
# seek to release the embargo).
#
# @example check whether a resource is under an active embargo
# manager = EmbargoManager.new(resource: my_resource)
Expand All @@ -21,9 +38,42 @@ module Hyrax
#
# manager = EmbargoManager.new(resource: resource)
#
# manager.apply
# manager.apply!
# manager.enforced? => true
# resource.visibility # => 'restricted'
#
# @example releasing an embargo
# embargo = Hyrax::Embargo.new(visibility_during_embargo: 'restricted',
# visibility_after_embargo: 'open',
# embargo_release_date: Time.zone.today + 1000)
#
# @example releasing an embargo
# embargo = Hyrax::Embargo.new(visibility_during_embargo: 'restricted',
# visibility_after_embargo: 'open',
# embargo_release_date: Time.zone.today + 1)
#
# resource = Hyrax::Resource.new(embargo: embargo)
# manager = EmbargoManager.new(resource: resource)
#
# manager.under_embargo? => true
# manager.enforced? => false
#
# manager.apply!
#
# resource.visibility # => 'restricted'
# manager.enforced? => true
#
# manager.release! # => NotReleasableError
#
# # <spongebob narrator>ONE DAY LATER</spongebob narrator>
# manager.under_embargo? => false
# manager.enforced? => true
#
# manager.release!
#
# resource.visibility # => 'open'
# manager.enforced? => false
#
class EmbargoManager
##
# @!attribute [rw] resource
Expand All @@ -48,10 +98,25 @@ def apply_embargo_for(resource:, query_service: Hyrax.query_service)
.apply
end

def apply_embargo_for!(resource:, query_service: Hyrax.query_service)
new(resource: resource, query_service: query_service)
.apply!
end

def embargo_for(resource:, query_service: Hyrax.query_service)
new(resource: resource, query_service: query_service)
.embargo
end

def release_embargo_for(resource:, query_service: Hyrax.query_service)
new(resource: resource, query_service: query_service)
.release
end

def release_embargo_for!(resource:, query_service: Hyrax.query_service)
new(resource: resource, query_service: query_service)
.release!
end
end

##
Expand All @@ -68,6 +133,8 @@ def copy_embargo_to(target:)
end

##
# Sets the visibility of the resource to the embargo's visibility condition
#
# @return [Boolean]
def apply
return false unless under_embargo?
Expand All @@ -76,17 +143,54 @@ def apply
end

##
# @return [Valkyrie::Resource]
# @return [void]
# @raise [NotEnforcableError] when trying to apply an embargo that isn't active
def apply!
apply || raise(NotEnforcableError)
end

##
# @return [Boolean]
def enforced?
embargo.visibility_during_embargo.to_s == resource.visibility
end

##
# @return [Hyrax::Embargo]
def embargo
resource.embargo || Embargo.new
end

##
# @return [Boolean]
# Sets the visibility of the resource to the embargo's visibility condition.
# no-op if the embargo period is current.
#
# @return [Boolean] truthy if the embargo has been applied
def release
return false if under_embargo?
return true if embargo.visibility_after_embargo.nil?

resource.visibility = embargo.visibility_after_embargo
end

##
# @return [void]
# @raise [NotEnforcableError] when trying to release an embargo that
# is currently active
def release!
release || raise(NotReleasableError)
end

##
# @return [Boolean] indicates whether the date range for the embargo's
# applicability includes the present date.
def under_embargo?
embargo.active?
end

class NotEnforcableError < RuntimeError; end
class NotReleasableError < RuntimeError; end

private

def clone_attributes
Expand Down
42 changes: 41 additions & 1 deletion app/services/hyrax/lease_manager.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# frozen_string_literal: true

module Hyrax
##
# Provides utilities for managing the lifecycle of an `Hyrax::Lease` on a
# `Hyrax::Resource`.
class LeaseManager
##
# @!attribute [rw] resource
Expand Down Expand Up @@ -31,6 +34,12 @@ def lease_for(resource:, query_service: Hyrax.query_service)
end
end

##
# Copies and applies the lease to a new (target) resource.
#
# @param target [Hyrax::Resource]
#
# @return [Boolean]
def copy_lease_to(target:)
return false unless under_lease?

Expand All @@ -47,17 +56,48 @@ def apply
end

##
# @return [Valkyrie::Resource]
# @return [void]
# @raise [NotEnforcableError] when trying to apply an lease that isn't active
def apply!
apply || raise(NotEnforcableError)
end

##
# @return [Boolean]
def enforced?
lease.visibility_during_lease.to_s == resource.visibility
end

##
# @return [Hyrax::Lease]
def lease
resource.lease || Lease.new
end

##
# @return [Boolean]
def release
return false if under_lease?
return true if lease.visibility_after_lease.nil?

resource.visibility = lease.visibility_after_lease
end

##
# @return [void]
def release!
release || raise(NotReleasableError)
end

##
# @return [Boolean]
def under_lease?
lease.active?
end

class NotEnforcableError < RuntimeError; end
class NotReleasableError < RuntimeError; end

private

def clone_attributes
Expand Down
72 changes: 70 additions & 2 deletions spec/services/hyrax/embargo_manager_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
end
end

context 'with expried embargo' do
context 'with expired embargo' do
include_context 'with expired embargo'

it 'is a no-op' do
Expand Down Expand Up @@ -52,7 +52,7 @@
.from nil
end

context 'with expried embargo' do
context 'with expired embargo' do
include_context 'with expired embargo'

it 'does not copy the embargo' do
Expand Down Expand Up @@ -83,6 +83,36 @@
end
end

describe '#enforced' do
it { is_expected.not_to be_enforced }

context 'when under embargo' do
include_context 'when under embargo'

it { is_expected.not_to be_enforced }

context 'and it is applied' do
before { manager.apply! }

it { is_expected.to be_enforced }
end
end

context 'with expired embargo' do
include_context 'with expired embargo'

it { is_expected.not_to be_enforced }
end

context 'with an embargo that is in force, but expired' do
include_context 'with expired embargo'

before { resource.visibility = embargo.visibility_during_embargo }

it { is_expected.to be_enforced }
end
end

describe '#embargo' do
it 'gives an inactive embargo' do
expect(manager.embargo).not_to be_active
Expand All @@ -105,6 +135,44 @@
end
end

describe '#release' do
context 'with no embargo' do
it 'is a no-op' do
expect { manager.release }
.not_to change { resource.visibility }
end
end

context 'with expired embargo' do
include_context 'with expired embargo'

it 'ensures the post-embargo visibility is set' do
manager.release
expect(resource.visibility).to eq embargo.visibility_after_embargo
end

context 'and embargo was applied' do
before { resource.visibility = embargo.visibility_during_embargo }

it 'ensures the post-embargo visibility is set' do
expect { manager.release }
.to change { resource.visibility }
.from(embargo.visibility_during_embargo)
.to embargo.visibility_after_embargo
end
end
end

context 'when under embargo' do
include_context 'when under embargo'

it 'is a no-op' do
expect { manager.release }
.not_to change { resource.visibility }
end
end
end

describe '#under_embargo?' do
it { is_expected.not_to be_under_embargo }

Expand Down
Loading