Skip to content

Commit 3ef440f

Browse files
tom johnsonTom Johnson
authored andcommitted
expand the EmbargoManager interface to handle releasing embargos
for Valkyrie models, we provide `Hyrax::EmbargoManager` to make the embargo lifecycle easy to work with. to date, this has only supported applying embargoes. this adds the ability to release an embargo after its period has expired. a concept of 'enforcement' is added, represented by `#enforced?`. this addresses the issue of embargoes which are not current (their period is past) but have not yet been released. the terminology used by the `EmbargoManager` is documented. see also: samvera/hydra-head#511.
1 parent d4fe3ae commit 3ef440f

File tree

2 files changed

+178
-6
lines changed

2 files changed

+178
-6
lines changed

app/services/hyrax/embargo_manager.rb

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,24 @@ module Hyrax
55
# Provides utilities for managing the lifecycle of an `Hyrax::Embargo` on a
66
# `Hyrax::Resource`.
77
#
8-
# This can do things like
8+
# The embargo terminology used here is as follows:
9+
#
10+
# - "Release Date" is the day an embargo is scheduled to be released.
11+
# - "Under Embargo" means the embargo is "active"; i.e. that its release
12+
# date is today or later.
13+
# - "Applied" means the embargo's pre-release visibility has been set on
14+
# the resource.
15+
# - "Released" means the embargo's post-release visibility has been set on
16+
# the resource.
17+
# - "Enforced" means the object's visibility matches the pre-release
18+
# visibility of the embargo; i.e. the embargo has been applied,
19+
# but not released.
20+
#
21+
# Note that an resource may be `#under_embargo?` even if the embargo is not
22+
# be `#enforced?` (in this case, the application should seek to apply the
23+
# embargo, e.g. via a scheduled job). Additionally, an embargo may be
24+
# `#enforced?` after its release date (in this case, the application should
25+
# seek to release the embargo).
926
#
1027
# @example check whether a resource is under an active embargo
1128
# manager = EmbargoManager.new(resource: my_resource)
@@ -21,9 +38,42 @@ module Hyrax
2138
#
2239
# manager = EmbargoManager.new(resource: resource)
2340
#
24-
# manager.apply
41+
# manager.apply!
42+
# manager.enforced? => true
2543
# resource.visibility # => 'restricted'
2644
#
45+
# @example releasing an embargo
46+
# embargo = Hyrax::Embargo.new(visibility_during_embargo: 'restricted',
47+
# visibility_after_embargo: 'open',
48+
# embargo_release_date: Time.zone.today + 1000)
49+
#
50+
# @example releasing an embargo
51+
# embargo = Hyrax::Embargo.new(visibility_during_embargo: 'restricted',
52+
# visibility_after_embargo: 'open',
53+
# embargo_release_date: Time.zone.today + 1)
54+
#
55+
# resource = Hyrax::Resource.new(embargo: embargo)
56+
# manager = EmbargoManager.new(resource: resource)
57+
#
58+
# manager.under_embargo? => true
59+
# manager.enforced? => false
60+
#
61+
# manager.apply!
62+
#
63+
# resource.visibility # => 'restricted'
64+
# manager.enforced? => true
65+
#
66+
# manager.release! # => NotReleasableError
67+
#
68+
# # <spongebob narrator>ONE DAY LATER</spongebob narrator>
69+
# manager.under_embargo? => false
70+
# manager.enforced? => true
71+
#
72+
# manager.release!
73+
#
74+
# resource.visibility # => 'open'
75+
# manager.enforced? => false
76+
#
2777
class EmbargoManager
2878
##
2979
# @!attribute [rw] resource
@@ -48,10 +98,25 @@ def apply_embargo_for(resource:, query_service: Hyrax.query_service)
4898
.apply
4999
end
50100

101+
def apply_embargo_for!(resource:, query_service: Hyrax.query_service)
102+
new(resource: resource, query_service: query_service)
103+
.apply!
104+
end
105+
51106
def embargo_for(resource:, query_service: Hyrax.query_service)
52107
new(resource: resource, query_service: query_service)
53108
.embargo
54109
end
110+
111+
def release_embargo_for(resource:, query_service: Hyrax.query_service)
112+
new(resource: resource, query_service: query_service)
113+
.release
114+
end
115+
116+
def release_embargo_for!(resource:, query_service: Hyrax.query_service)
117+
new(resource: resource, query_service: query_service)
118+
.release!
119+
end
55120
end
56121

57122
##
@@ -68,6 +133,8 @@ def copy_embargo_to(target:)
68133
end
69134

70135
##
136+
# Sets the visibility of the resource to the embargo's visibility condition
137+
#
71138
# @return [Boolean]
72139
def apply
73140
return false unless under_embargo?
@@ -76,17 +143,54 @@ def apply
76143
end
77144

78145
##
79-
# @return [Valkyrie::Resource]
146+
# @return [void]
147+
# @raise [NotEnforcableError] when trying to apply an embargo that isn't active
148+
def apply!
149+
apply || raise(NotEnforcableError)
150+
end
151+
152+
##
153+
# @return [Boolean]
154+
def enforced?
155+
embargo.visibility_during_embargo.to_s == resource.visibility
156+
end
157+
158+
##
159+
# @return [Hyrax::Embargo]
80160
def embargo
81161
resource.embargo || Embargo.new
82162
end
83163

84164
##
85-
# @return [Boolean]
165+
# Sets the visibility of the resource to the embargo's visibility condition.
166+
# no-op if the embargo period is current.
167+
#
168+
# @return [Boolean] truthy if the embargo has been applied
169+
def release
170+
return false if under_embargo?
171+
return true if embargo.visibility_after_embargo.nil?
172+
173+
resource.visibility = embargo.visibility_after_embargo
174+
end
175+
176+
##
177+
# @return [void]
178+
# @raise [NotEnforcableError] when trying to release an embargo that
179+
# is currently active
180+
def release!
181+
release || raise(NotReleasableError)
182+
end
183+
184+
##
185+
# @return [Boolean] indicates whether the date range for the embargo's
186+
# applicability includes the present date.
86187
def under_embargo?
87188
embargo.active?
88189
end
89190

191+
class NotEnforcableError < RuntimeError; end
192+
class NotReleasableError < RuntimeError; end
193+
90194
private
91195

92196
def clone_attributes

spec/services/hyrax/embargo_manager_spec.rb

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
end
2222
end
2323

24-
context 'with expried embargo' do
24+
context 'with expired embargo' do
2525
include_context 'with expired embargo'
2626

2727
it 'is a no-op' do
@@ -52,7 +52,7 @@
5252
.from nil
5353
end
5454

55-
context 'with expried embargo' do
55+
context 'with expired embargo' do
5656
include_context 'with expired embargo'
5757

5858
it 'does not copy the embargo' do
@@ -83,6 +83,36 @@
8383
end
8484
end
8585

86+
describe '#enforced' do
87+
it { is_expected.not_to be_enforced }
88+
89+
context 'when under embargo' do
90+
include_context 'when under embargo'
91+
92+
it { is_expected.not_to be_enforced }
93+
94+
context 'and it is applied' do
95+
before { manager.apply! }
96+
97+
it { is_expected.to be_enforced }
98+
end
99+
end
100+
101+
context 'with expired embargo' do
102+
include_context 'with expired embargo'
103+
104+
it { is_expected.not_to be_enforced }
105+
end
106+
107+
context 'with an embargo that is in force, but expired' do
108+
include_context 'with expired embargo'
109+
110+
before { resource.visibility = embargo.visibility_during_embargo }
111+
112+
it { is_expected.to be_enforced }
113+
end
114+
end
115+
86116
describe '#embargo' do
87117
it 'gives an inactive embargo' do
88118
expect(manager.embargo).not_to be_active
@@ -105,6 +135,44 @@
105135
end
106136
end
107137

138+
describe '#release' do
139+
context 'with no embargo' do
140+
it 'is a no-op' do
141+
expect { manager.release }
142+
.not_to change { resource.visibility }
143+
end
144+
end
145+
146+
context 'with expired embargo' do
147+
include_context 'with expired embargo'
148+
149+
it 'ensures the post-embargo visibility is set' do
150+
manager.release
151+
expect(resource.visibility).to eq embargo.visibility_after_embargo
152+
end
153+
154+
context 'and embargo was applied' do
155+
before { resource.visibility = embargo.visibility_during_embargo }
156+
157+
it 'ensures the post-embargo visibility is set' do
158+
expect { manager.release }
159+
.to change { resource.visibility }
160+
.from(embargo.visibility_during_embargo)
161+
.to embargo.visibility_after_embargo
162+
end
163+
end
164+
end
165+
166+
context 'when under embargo' do
167+
include_context 'when under embargo'
168+
169+
it 'is a no-op' do
170+
expect { manager.release }
171+
.not_to change { resource.visibility }
172+
end
173+
end
174+
end
175+
108176
describe '#under_embargo?' do
109177
it { is_expected.not_to be_under_embargo }
110178

0 commit comments

Comments
 (0)