Skip to content

Commit

Permalink
Merge pull request #6127 from samvera/6126-deactivated-leases
Browse files Browse the repository at this point in the history
6126 deactivated leases
  • Loading branch information
alishaevn committed Aug 4, 2023
2 parents 92ead3a + 96f5719 commit 1375e95
Show file tree
Hide file tree
Showing 28 changed files with 278 additions and 66 deletions.
7 changes: 4 additions & 3 deletions app/actors/hyrax/actors/base_actor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def apply_deposit_date(env)
def save(env, use_valkyrie: false)
return env.curation_concern.save unless use_valkyrie

resource = valkyrie_save(resource: env.curation_concern.valkyrie_resource)
# don't run validations again on the converted object if they've already passed
resource = valkyrie_save(resource: env.curation_concern.valkyrie_resource, is_valid: env.curation_concern.save)

# we need to manually set the id and reload, because the actor stack requires
# `env.curation_concern` to be the exact same instance throughout.
Expand Down Expand Up @@ -115,9 +116,9 @@ def multivalued_form_attributes(attributes)
attributes.select { |_, v| v.respond_to?(:select) && !v.respond_to?(:read) }
end

def valkyrie_save(resource:)
def valkyrie_save(resource:, is_valid:)
permissions = resource.permission_manager.acl.permissions
resource = Hyrax.persister.save(resource: resource)
resource = Hyrax.persister.save(resource: resource, perform_af_validation: !is_valid)

resource.permission_manager.acl.permissions = permissions
resource.permission_manager.acl.save
Expand Down
7 changes: 5 additions & 2 deletions app/actors/hyrax/actors/lease_actor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ def destroy
case work
when Valkyrie::Resource
lease_manager = Hyrax::LeaseManager.new(resource: work)
lease_manager.release && Hyrax::AccessControlList(work).save
lease_manager.nullify
return if lease_manager.lease.lease_expiration_date.blank?

lease_manager.deactivate!
work.lease = Hyrax.persister.save(resource: lease_manager.lease)
Hyrax::AccessControlList(work).save
else
work.lease_visibility! # If the lease has lapsed, update the current visibility.
work.deactivate_lease!
Expand Down
8 changes: 6 additions & 2 deletions app/controllers/concerns/hyrax/works_controller_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,18 @@ def actor

##
# @return [#errors]
# rubocop:disable Metrics/MethodLength
def create_valkyrie_work
form = build_form
return after_create_error(form_err_msg(form)) unless form.validate(params[hash_key_for_curation_concern])
# fallback to an empty hash to avoid: # NoMethodError: undefined method `has_key?` for nil:NilClass
original_input_params_for_form = params[hash_key_for_curation_concern] ? params[hash_key_for_curation_concern] : {}
return after_create_error(form_err_msg(form), original_input_params_for_form) unless form.validate(original_input_params_for_form)

result =
transactions['change_set.create_work']
.with_step_args(
'work_resource.add_to_parent' => { parent_id: params[:parent_id], user: current_user },
'work_resource.add_file_sets' => { uploaded_files: uploaded_files, file_set_params: params[hash_key_for_curation_concern][:file_set] },
'work_resource.add_file_sets' => { uploaded_files: uploaded_files, file_set_params: original_input_params_for_form[:file_set] },
'change_set.set_user_as_depositor' => { user: current_user },
'work_resource.change_depositor' => { user: ::User.find_by_user_key(form.on_behalf_of) },
'work_resource.save_acl' => { permissions_params: form.input_params["permissions"] }
Expand All @@ -197,6 +200,7 @@ def create_valkyrie_work
@curation_concern = result.value_or { return after_create_error(transaction_err_msg(result)) }
after_create_response
end
# rubocop:enable Metrics/MethodLength

def update_valkyrie_work
form = build_form
Expand Down
1 change: 1 addition & 0 deletions app/forms/hyrax/forms/work_lease_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Forms
# +LeasesControllerBehavior+.
class WorkLeaseForm < Hyrax::ChangeSet
property :lease, form: Hyrax::Forms::Lease, populator: :lease_populator, prepopulator: :lease_populator
property :lease_history, virtual: true, prepopulator: proc { |_opts| self.lease_history = model.lease&.lease_history }
property :lease_expiration_date, virtual: true, prepopulator: proc { |_opts| self.lease_expiration_date = model.lease&.lease_expiration_date }
property :visibility_after_lease, virtual: true, prepopulator: proc { |_opts| self.visibility_after_lease = model.lease&.visibility_after_lease }
property :visibility_during_lease, virtual: true, prepopulator: proc { |_opts| self.visibility_during_lease = model.lease&.visibility_during_lease }
Expand Down
14 changes: 14 additions & 0 deletions app/indexers/hyrax/valkyrie_file_set_indexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def to_solr # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Met
solr_doc['hasRelatedMediaFragment_ssim'] = resource.representative_id.to_s
solr_doc['hasRelatedImage_ssim'] = resource.thumbnail_id.to_s

index_lease(solr_doc)

# Add in metadata from the original file.
file_metadata = Hyrax::FileSetFileService.new(file_set: resource).original_file
return solr_doc unless file_metadata
Expand Down Expand Up @@ -116,5 +118,17 @@ def file_format(file)
file.format_label
end
end

def index_lease(doc)
if resource.lease&.active?
doc['lease_expiration_date_dtsi'] = resource.lease.lease_expiration_date&.to_datetime
doc['visibility_after_lease_ssim'] = resource.lease.visibility_after_lease
doc['visibility_during_lease_ssim'] = resource.lease.visibility_during_lease
else
doc['lease_history_ssim'] = resource&.lease&.lease_history
end

doc
end
end
end
4 changes: 3 additions & 1 deletion app/indexers/hyrax/valkyrie_work_indexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ def index_embargo(doc)
end

def index_lease(doc)
if Hyrax::LeaseManager.new(resource: resource).under_lease?
if resource.lease&.active?
doc['lease_expiration_date_dtsi'] = resource.lease.lease_expiration_date&.to_datetime
doc['visibility_after_lease_ssim'] = resource.lease.visibility_after_lease
doc['visibility_during_lease_ssim'] = resource.lease.visibility_during_lease
else
doc['lease_history_ssim'] = resource&.lease&.lease_history
end

doc
Expand Down
14 changes: 13 additions & 1 deletion app/models/hyrax/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Resource < Valkyrie::Resource

attribute :alternate_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID)
attribute :embargo_id, Valkyrie::Types::ID
attribute :lease, Hyrax::Lease.optional
attribute :lease_id, Valkyrie::Types::ID

delegate :edit_groups, :edit_groups=,
:edit_users, :edit_users=,
Expand Down Expand Up @@ -119,6 +119,18 @@ def embargo
@embargo = Hyrax.query_service.find_by(id: embargo_id) if embargo_id.present?
end

def lease=(value)
raise TypeError "can't convert #{value.class} into Hyrax::Lease" unless value.is_a? Hyrax::Lease

@lease = value
self.lease_id = @lease.id
end

def lease
return @lease if @lease
@lease = Hyrax.query_service.find_by(id: lease_id) if lease_id.present?
end

protected

def visibility_writer
Expand Down
9 changes: 6 additions & 3 deletions app/services/hyrax/embargo_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ def deactivate!
embargo_record = embargo_history_message(
embargo_state,
Time.zone.today,
DateTime.parse(embargo.embargo_release_date),
embargo.embargo_release_date,
embargo.visibility_during_embargo,
embargo.visibility_after_embargo
)

nullify(force: true)
release(force: true)
nullify(force: true)
embargo.embargo_history += [embargo_record]
end

Expand Down Expand Up @@ -180,14 +180,17 @@ def embargo
end

##
# Drop the embargo by setting its release date to `nil`.
# Drop the embargo by setting its release date and visibility settings to `nil`.
#
# @param force [boolean] force the nullify even when the embargo period is current
#
# @return [void]
def nullify(force: false)
return false if !force && under_embargo?

embargo.embargo_release_date = nil
embargo.visibility_during_embargo = nil
embargo.visibility_after_embargo = nil
end

##
Expand Down
96 changes: 88 additions & 8 deletions app/services/hyrax/lease_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,22 @@ module Hyrax
##
# Provides utilities for managing the lifecycle of an `Hyrax::Lease` on a
# `Hyrax::Resource`.
class LeaseManager
#
# The lease terminology used here is as follows:
#
# - "Expiration Date" is the day a lease is scheduled to expire.
# - "Under Lease" means the lease is "active"; i.e. that its expiration
# date is today or later.
# - "Applied" means the lease's pre-expiration visibility has been set on
# the resource.
# - "Released" means the lease's post-expiration visibility has been set on
# the resource.
# - "Enforced" means the object's visibility matches the pre-expiration
# visibility of the lease; i.e. the lease has been applied,
# but not released.
# - "Deactivate" means that the existing lease will be removed
#
class LeaseManager # rubocop:disable Metrics/ClassLength
##
# @!attribute [rw] resource
# @return [Hyrax::Resource]
Expand Down Expand Up @@ -47,6 +62,51 @@ def release_lease_for!(resource:, query_service: Hyrax.query_service)
new(resource: resource, query_service: query_service)
.release!
end

# Creates or updates an existing lease on a member to match the lease on the parent work
# @param [Array<Valkyrie::Resource>] members
# @param [Hyrax::Work] work
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def create_or_update_lease_on_members(members, work)
# TODO: account for all members and levels, not just file sets. ref: #6131

members.each do |member|
member_lease_needs_updating = work.lease.updated_at > member.lease&.updated_at if member.lease

if member.lease && member_lease_needs_updating
member.lease.lease_expiration_date = work.lease['lease_expiration_date']
member.lease.visibility_during_lease = work.lease['visibility_during_lease']
member.lease.visibility_after_lease = work.lease['visibility_after_lease']
member.lease = Hyrax.persister.save(resource: member.lease)
else
work_lease_manager = Hyrax::LeaseManager.new(resource: work)
work_lease_manager.copy_lease_to(target: member)
member = Hyrax.persister.save(resource: member)
end

user ||= ::User.find_by_user_key(member.depositor)
# the line below works in that it indexes the file set with the necessary lease properties
# I do not know however if this is the best event_id to pass
Hyrax.publisher.publish('object.metadata.updated', object: member, user: user)
end
end
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
end

# Deactivates the lease and logs a message to the lease_history property
def deactivate!
lease_state = lease.active? ? 'active' : 'expired'
lease_record = lease_history_message(
lease_state,
Time.zone.today,
lease.lease_expiration_date,
lease.visibility_during_lease,
lease.visibility_after_lease
)

release(force: true)
nullify(force: true)
lease.lease_history += [lease_record]
end

##
Expand All @@ -58,7 +118,7 @@ def release_lease_for!(resource:, query_service: Hyrax.query_service)
def copy_lease_to(target:)
return false unless under_lease?

target.lease = Lease.new(clone_attributes)
target.lease = Hyrax.persister.save(resource: Lease.new(clone_attributes))
self.class.apply_lease_for(resource: target)
end

Expand All @@ -80,7 +140,8 @@ def apply!
##
# @return [Boolean]
def enforced?
lease.visibility_during_lease.to_s == resource.visibility
lease.lease_expiration_date.present? &&
lease.visibility_during_lease.to_s == resource.visibility
end

##
Expand All @@ -90,18 +151,27 @@ def lease
end

##
# Drop the lease by setting its release date to `nil`.
# Drop the lease by setting its release date and visibility settings to `nil`.
#
# @param force [boolean] force the nullify even when the lease period is current
# @return [void]
def nullify
return unless under_lease?
def nullify(force: false)
return false if !force && under_lease?

lease.lease_expiration_date = nil
lease.visibility_during_lease = nil
lease.visibility_after_lease = nil
end

##
# Sets the visibility of the resource to the lease's after lease visibility.
# no-op if the lease period is current and the force flag is false.
#
# @param force [boolean] force the release even when the lease period is current
#
# @return [Boolean]
def release
return false if under_lease?
def release(force: false)
return false if !force && under_lease?
return true if lease.visibility_after_lease.nil?

resource.visibility = lease.visibility_after_lease
Expand Down Expand Up @@ -131,5 +201,15 @@ def clone_attributes
def core_attribute_keys
[:visibility_after_lease, :visibility_during_lease, :lease_expiration_date]
end

# Create the log message used when deactivating a lease
def lease_history_message(state, deactivate_date, expiration_date, visibility_during, visibility_after)
I18n.t 'hydra.lease.history_message',
state: state,
deactivate_date: deactivate_date,
expiration_date: expiration_date,
visibility_during: visibility_during,
visibility_after: visibility_after
end
end
end
2 changes: 1 addition & 1 deletion app/views/hyrax/base/_form_permission_lease.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="form-inline">
<%= visibility_badge(Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_LEASE) %>
<%= f.input :visibility_during_lease, wrapper: :inline, collection: visibility_options(:loosen), include_blank: false %>
<%= f.input :lease_expiration_date, wrapper: :inline, input_html: { value: f.object.lease_expiration_date || Date.tomorrow, class: 'datepicker' } %>
<%= f.input :lease_expiration_date, wrapper: :inline, input_html: { value: f.object.lease_expiration_date&.to_date || Date.tomorrow, class: 'datepicker' } %>
<%= f.input :visibility_after_lease, wrapper: :inline, collection: visibility_options(:restrict), include_blank: false %>
</div>
4 changes: 2 additions & 2 deletions app/views/hyrax/base/_form_visibility_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<div class="form-inline">
<%= f.input :visibility_during_embargo, wrapper: :inline, collection: visibility_options(:restrict), include_blank: false %>
<%= t('hyrax.works.form.visibility_until') %>
<%= f.date_field :embargo_release_date, wrapper: :inline, value: f.object.embargo_release_date || Date.tomorrow, class: 'datepicker form-control' %>
<%= f.date_field :embargo_release_date, wrapper: :inline, value: f.object.embargo_release_date&.to_date || Date.tomorrow, class: 'datepicker form-control' %>
<%= f.input :visibility_after_embargo, wrapper: :inline, collection: visibility_options(:loosen), include_blank: false %>
</div>
</div>
Expand All @@ -55,7 +55,7 @@
<div class="form-inline">
<%= f.input :visibility_during_lease, wrapper: :inline, collection: visibility_options(:loosen), include_blank: false %>
<%= t('hyrax.works.form.visibility_until') %>
<%= f.date_field :lease_expiration_date, wrapper: :inline, value: f.object.lease_expiration_date || Date.tomorrow, class: 'datepicker form-control' %>
<%= f.date_field :lease_expiration_date, wrapper: :inline, value: f.object.lease_expiration_date&.to_date || Date.tomorrow, class: 'datepicker form-control' %>
<%= f.input :visibility_after_lease, wrapper: :inline, collection: visibility_options(:restrict), include_blank: false %>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions lib/hyrax/transactions/steps/add_file_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ def initialize(handler: Hyrax::WorkUploadsHandler)
# @return [Dry::Monads::Result]
def call(obj, uploaded_files: [], file_set_params: [])
if @handler.new(work: obj).add(files: uploaded_files, file_set_params: file_set_params).attach
if obj.lease
file_sets = obj.member_ids.map do |member|
Hyrax.query_service.find_by(id: member) if Hyrax.query_service.find_by(id: member).is_a? Hyrax::FileSet
end

Hyrax::LeaseManager.create_or_update_lease_on_members(file_sets, obj)
end

Success(obj)
else
Failure[:failed_to_attach_file_sets, uploaded_files]
Expand Down
Loading

0 comments on commit 1375e95

Please sign in to comment.