Skip to content

Commit

Permalink
add metadata-only visibility (#704)
Browse files Browse the repository at this point in the history
* add metadata-only visibility to our models

* add specs

* first pass @ porting view labels from #701

* typo fixes and cleanup

* 2 complex 4 rubo

* helper specs

* we need to enforce html_safe in the helper

* some refactoring / make private things undiscoverable

* ensure authenticated items are discoverable

* fix + spec hyrax/permission_badge modification

* improve SolrDocument#visibility

* a little refactoring

* regenerate thumbnails after clearing embargos/leases

* remove embargo/lease info from catalog_controller index fields

* cleanup catalog_helper_spec
  • Loading branch information
rococodogs authored Mar 19, 2021
1 parent e412412 commit 0a51f39
Show file tree
Hide file tree
Showing 30 changed files with 620 additions and 52 deletions.
6 changes: 0 additions & 6 deletions app/controllers/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,6 @@ class CatalogController < ApplicationController
config.add_index_field 'license_tesim',
helper_method: :license_links,
label: :'blacklight.search.fields.license'
config.add_index_field 'embargo_release_date_dtsi',
label: :'blacklight.search.fields.embargo_release_date',
helper_method: :human_readable_date
config.add_index_field 'lease_expiration_date_dtsi',
label: :'blacklight.search.fields.lease_expiration_date',
helper_method: :human_readable_date

#
# search field configuration
Expand Down
26 changes: 26 additions & 0 deletions app/helpers/spot/ability_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Spot
module AbilityHelper
# Select options for visibility. Overwriting the original method to add our metadata-only
# visibility as an option.
#
# @return [Array<Array<String, String>>]
def visibility_options(variant)
options = [
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC,
'metadata',
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED,
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
]

case variant
when :restrict
options.delete_at(0)
# options.reverse!
when :loosen
options.delete_at(2)
end
options.map { |value| [visibility_text(value), value] }
end
end
end
38 changes: 33 additions & 5 deletions app/helpers/spot/catalog_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,42 @@ module CatalogHelper
# Falls back to the original value.
#
# @return [String]
# rubocop:disable Style/RescueModifier
def humanize_edtf_values(args)
Array.wrap(args[:value]).map { |val| humanize_edtf_value(val) }.to_sentence
Array.wrap(args[:value]).map { |value| Date.edtf(value).humanize rescue value }.to_sentence
end
# rubocop:enable Style/RescueModifier

def humanize_edtf_value(value)
Date.edtf(value).humanize
rescue
value
# Should we display an info alert to catalog results?
#
# @param [SolrDocument]
# @return [true, false]
def display_info_alert?(document)
document.embargo_release_date.present? ||
document.lease_expiration_date.present? ||
document.registered? ||
document.metadata_only?
end

# @param [SolrDocument]
# @return [String]
def document_access_display_text(document)
key = if document.embargo_release_date.present?
:embargo
elsif document.lease_expiration_date.present?
:lease
elsif document.registered?
:authenticated
elsif document.metadata_only?
:metadata
else
:default # not expecting to get here, but we should have a generic message just in case
end

date_method = [:embargo_release_date, :lease_expiration_date].find { |m| document.send(m).present? }
date = document.send(date_method).strftime('%B %e, %Y') unless date_method.nil?

I18n.t("#{key}_html", scope: ['spot', 'work', 'access_message'], date: date).html_safe
end
end
end
2 changes: 1 addition & 1 deletion app/jobs/clear_expired_embargoes_and_leases_job.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true
class ClearExpiredEmbargoesAndLeasesJob < ApplicationJob
def perform
::Spot::EmbargoLeaseService.clear_all_expired
::Spot::EmbargoLeaseService.clear_all_expired(regenerate_thumbnails: true)
end
end
21 changes: 21 additions & 0 deletions app/jobs/spot/regenerate_thumbnail_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true
module Spot
# Job that allows us to recreate thumbnails without having to run the entirety of
# +CreateDerivativesJob+ which generates pyramidal tiffs, extracts full-text content,
# basically a whole lot of work that we might not need to repeat.
class RegenerateThumbnailJob < ApplicationJob
def perform(work)
return if work&.thumbnail_id.nil?
file_set = FileSet.find(work.thumbnail_id)

filename = Hyrax::DerivativePath.derivative_path_for_reference(file_set, 'thumbnail')
Spot::Derivatives::ThumbnailService.new(file_set).create_derivatives(filename)

file_set.reload
file_set.update_index
work.update_index

true
end
end
end
58 changes: 58 additions & 0 deletions app/models/concerns/spot/metadata_only_visibility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true
module Spot
# mixin to enable a 'metadata' visibility, intended to be interpreted as:
# - the work's metadata is visible
# - the work's files are only visible to admins
module MetadataOnlyVisibility
extend ActiveSupport::Concern

# @return [void]
# @see https://github.com/samvera/hydra-head/blob/v11.0.0/hydra-access-controls/app/models/concerns/hydra/access_controls/visibility.rb#L5-L18
def visibility=(value)
return super unless value == 'metadata'

# setup our discover/read groups
metadata_only_visibility!

# need to set this manually, as +super+ would be doing that work
@visibility = value
end

# @return [String]
# @see https://github.com/samvera/hydra-head/blob/v11.0.0/hydra-access-controls/app/models/concerns/hydra/access_controls/visibility.rb#L20-L28
def visibility
return 'metadata' if !public? && discover_groups.include?(Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC)

super
end

private

def set_visibility_discover_groups
set_discover_groups([Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC], discover_groups)
end

# Sets discover groups to +['public']+ and read groups to +['admin']+ only
#
# @return [void]
def metadata_only_visibility!
visibility_will_change! unless visibility == 'metadata'
set_visibility_discover_groups
set_read_groups([Ability.admin_group_name], read_groups)
end

# Be sure to remove the ['public'] from discover_groups if we're making this work private
#
# @return [void]
def private_visibility!
super
set_discover_groups([], discover_groups)
end

# Ensure unauthenticated users are able to view metadata of authenticated items.
def registered_visibility!
super
set_visibility_discover_groups
end
end
end
1 change: 1 addition & 0 deletions app/models/concerns/spot/solr_document_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module SolrDocumentAttributes
attribute :date_issued, ::Blacklight::Types::Array, 'date_issued_ssim'
attribute :depositor, ::Blacklight::Types::String, 'depositor_ssim'
attribute :description, ::Blacklight::Types::Array, 'description_tesim'
attribute :discover_groups, ::Blacklight::Types::Array, ::Ability.discover_group_field
attribute :division, ::Blacklight::Types::Array, 'division_tesim'
attribute :donor, ::Blacklight::Types::Array, 'donor_ssim'
attribute :editor, ::Blacklight::Types::Array, 'editor_tesim'
Expand Down
1 change: 1 addition & 0 deletions app/models/concerns/spot/work_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module WorkBehavior
include ::Hyrax::WorkBehavior
include NoidIdentifier
include CoreMetadata
include MetadataOnlyVisibility

included do
# The `controlled_properties` attribute is used by the Hyrax::DeepIndexingService,
Expand Down
1 change: 1 addition & 0 deletions app/models/file_set.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class FileSet < ActiveFedora::Base
include ::Hyrax::FileSetBehavior
include ::Spot::MetadataOnlyVisibility

# using our own FileSetIndexer that doesn't index full-text content
self.indexer = Spot::FileSetIndexer
Expand Down
32 changes: 32 additions & 0 deletions app/models/solr_document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ def self.field_semantics
end
# rubocop:enable Metrics/MethodLength

# Less involved than the same method on WorkShowPresenters,
# all we want to know is if the item's visibility is "metadata"
#
# @return [true, false]
def discoverable?
public? || discover_groups.include?(Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC)
end

def metadata_only?
visibility == 'metadata'
end

def sets
Spot::OaiCollectionSolrSet.sets_for(self)
end
Expand All @@ -73,4 +85,24 @@ def to_param
return collection_slug if collection? && collection_slug.present?
super
end

# Override Hyrax::SolrDocumentBehavior#visibility to add our custom metadata-only
# visibility as an option when discover_groups include 'public'
#
# @return [String]
def visibility
@visibility ||= if embargo_release_date.present?
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_EMBARGO
elsif lease_expiration_date.present?
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_LEASE
elsif public?
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
elsif registered?
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
elsif discoverable?
'metadata'
else
Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
end
end
end
49 changes: 30 additions & 19 deletions app/presenters/spot/base_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ class BasePresenter < ::Hyrax::WorkShowPresenter
# to add their unique fields
delegate :contributor, :creator, :description, :identifier, :keyword, :language,
:language_label, :location, :note, :permalink, :physical_medium,
:publisher, :related_resource, :resource_type, :rights_holder, :rights_statement,
:publisher, :registered?, :related_resource, :resource_type, :rights_holder, :rights_statement,
:source, :subject, :subtitle, :title_alternative, :title,
:visibility,
to: :solr_document

delegate :public?, to: :solr_document

# @return [String]
def export_all_text
I18n.t("spot.work.export.download_work_and_metadata_#{multiple_members? ? 'multiple' : 'single'}")
Expand All @@ -37,6 +39,11 @@ def export_formats
%i[csv ttl nt jsonld]
end

# @return [Array<Spot::Identifier>]
def local_identifier
@local_identifier ||= solr_document.local_identifier.map { |id| Spot::Identifier.from_string(id) }
end

# location values + labels zipped into tuples.
#
# @example
Expand All @@ -48,14 +55,11 @@ def location
solr_document.location.zip(solr_document.location_label).reject(&:empty?)
end

# @return [Array<Spot::Identifier>]
def local_identifier
@local_identifier ||= solr_document.local_identifier.map { |id| Spot::Identifier.from_string(id) }
end

# @return [Array<Spot::Identifier>]
def standard_identifier
@standard_identifier ||= solr_document.standard_identifier.map { |id| Spot::Identifier.from_string(id) }
# Check if an item's record should include files or just display the metadata.
#
# @return [true, false]
def metadata_only?
@metadata_only ||= metadata_only_flag
end

# @return [true, false]
Expand All @@ -71,11 +75,14 @@ def page_title
"#{title.first} // #{I18n.t('hyrax.product_name')}"
end

# Is the document's visibility public?
#
# @return [true, false]
def public?
solr_document.visibility == ::Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
# @return [Array<Array<String>>]
def rights_statement_merged
solr_document.rights_statement.zip(solr_document.rights_statement_label)
end

# @return [Array<Spot::Identifier>]
def standard_identifier
@standard_identifier ||= solr_document.standard_identifier.map { |id| Spot::Identifier.from_string(id) }
end

# Subject URIs and Labels in an array of tuples
Expand All @@ -88,11 +95,6 @@ def subject
solr_document.subject.zip(solr_document.subject_label)
end

# @return [Array<Array<String>>]
def rights_statement_merged
solr_document.rights_statement.zip(solr_document.rights_statement_label)
end

# For now, overriding the ability to feature individual works
# on the homepage. This should prevent the 'Feature'/'Unfeature'
# button from rendering on the work edit page.
Expand All @@ -101,5 +103,14 @@ def rights_statement_merged
def work_featurable?
false
end

private

def metadata_only_flag
return false if public? || current_ability.admin?
return false if registered? && current_ability.user_groups.include?(Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED)

true
end
end
end
12 changes: 8 additions & 4 deletions app/services/spot/embargo_lease_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class << self
# @return [void]
# @see {.clear_expired_embargoes}
# @see {.clear_expired_leases}
def clear_all_expired
clear_expired_embargoes && clear_expired_leases
def clear_all_expired(regenerate_thumbnails: false)
clear_expired_embargoes(regenerate_thumbnails: regenerate_thumbnails) && clear_expired_leases(regenerate_thumbnails: regenerate_thumbnails)
end

# Clears out expired embargoes and sets the +date_available+ property
# to today's date.
#
# @return [void]
def clear_expired_embargoes
def clear_expired_embargoes(regenerate_thumbnails: false)
::Hyrax::EmbargoService.assets_with_expired_embargoes.each do |presenter|
item = ActiveFedora::Base.find(presenter.id)

Expand All @@ -40,13 +40,15 @@ def clear_expired_embargoes
item.date_available = [Time.zone.now.strftime('%Y-%m-%d')] if item.respond_to?(:date_available=)
item.copy_visibility_to_files
item.save!

RegenerateThumbnailJob.perform_later(item) if regenerate_thumbnails == true
end
end

# Clears out expired leases
#
# @return [void]
def clear_expired_leases
def clear_expired_leases(regenerate_thumbnails: false)
::Hyrax::LeaseService.assets_with_expired_leases.each do |presenter|
item = ActiveFedora::Base.find(presenter.id)

Expand All @@ -55,6 +57,8 @@ def clear_expired_leases
::Hyrax::Actors::LeaseActor.new(item).destroy

item.copy_visibility_to_files unless item.is_a? FileSet

RegenerateThumbnailJob.perform_later(item) if regenerate_thumbnails == true
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions app/views/catalog/_index_header_list_default.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="search-results-title-row">
<h4 class="search-result-title"><%= link_to(document.title_or_label, document) %></h4>
<% if display_info_alert?(document) %>
<div class="alert alert-warning" style="margin:0; padding:5px;">
<%= document_access_display_text(document) %>
</div>
<% end %>
</div>
Loading

0 comments on commit 0a51f39

Please sign in to comment.