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

[i335] - port over serverless code from nnp #198

Merged
merged 6 commits into from
Mar 24, 2023
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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ IiifPrint supports:
* configuring how the manifest canvases are sorted in the viewer
* adding metadata fields to the manifest with faceted search links and external links
* excluding specified work types to be found in the catalog search
* external IIIF image urls that work with services such as serverless-iiif or cantaloup

A complete list of features can be found [here](https://github.com/scientist-softserv/iiif_print/wiki/Features-List).

Expand Down Expand Up @@ -92,6 +93,10 @@ IiifPrint easily integrates with your Hyrax 2.x applications.
## Configuration to enable IiifPrint features
**NOTE: WorkTypes and models are used synonymously here.**

### IIIF URL configuration

If you set EXTERNAL_IIIF_URL in your environment, then IiifPrint will use that URL as the root for your IIIF URLs. It will also switch from using the file set ID to using the SHA1 of the file as the identifier. This enables using serverless_iiif or Cantaloupe (refered to as the service) by pointing the service to the same S3 bucket that FCREPO writes the uploaded files to. By setting it up that way you do not need the service to connect to FCREPO or Hyrax at all, both natively support connecting to an S3 bucket to get their data.

### Model level configurations

In `app/models/{work_type}.rb` add `include IiifPrint.model_configuration` to any work types which require IiifPrint processing features (such as PDF splitting or OCR derivatives). See [lib/iiif_print.rb](./lib/iiif_print.rb) for details on configuration options.
Expand Down Expand Up @@ -153,7 +158,7 @@ TO ENABLE OCR Search (from the UV and catalog search)
}
```

To remove child works from recent works on homepage
To remove child works from recent works on homepage
### homepage_controller.rb
* In the HomepageController, change the search_builder_class to remove works from recent_documents if `is_child_bsi: true`
```rb
Expand Down
8 changes: 8 additions & 0 deletions app/indexers/concerns/iiif_print/file_set_indexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@ def generate_solr_document
text = text.tr("\n", ' ').squeeze(' ')
solr_doc['all_text_timv'] = text
solr_doc['all_text_tsimv'] = text
solr_doc['digest_ssim'] = digest_from_content
end
end

private

def digest_from_content
return unless object.original_file
object.original_file.digest.first.to_s
end
end
end
5 changes: 5 additions & 0 deletions app/models/concerns/iiif_print/solr/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module IiifPrint::Solr::Document
def self.decorate(base)
base.prepend(self)
base.send(:attribute, :is_child, Hyrax::SolrDocument::Metadata::Solr::String, 'is_child_bsi')
base.send(:attribute, :digest, Hyrax::SolrDocument::Metadata::Solr::String, 'digest_ssim')

# @note These properties came from the newspaper_works gem. They are configurable.
base.class_attribute :iiif_print_solr_field_names, default: %w[alternative_title genre
Expand All @@ -31,6 +32,10 @@ def self.decorate(base)
base
end

def digest_sha1
digest[/urn:sha1:([\w]+)/, 1]
end

def method_missing(method_name, *args, &block)
super unless iiif_print_solr_field_names.include? method_name.to_s
self[::ActiveFedora.index_field_mapper.solr_name(method_name.to_s)]
Expand Down
102 changes: 101 additions & 1 deletion app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ module IiifPrint
module IiifManifestPresenterBehavior
extend ActiveSupport::Concern

# Extending the presenter to the base url which includes the protocol.
# We need the base url to render the facet links and normalize the interface.
attr_accessor :base_url

def manifest_metadata
@manifest_metadata ||= IiifPrint.manifest_metadata_from(work: model, presenter: self)
end
Expand All @@ -11,7 +15,7 @@ def search_service
Rails.application.routes.url_helpers.solr_document_iiif_search_url(id, host: hostname)
end

# OVERRIDE Hyrax 3x, avoid nil returning to IIIF Manifest gem
# OVERRIDE: Hyrax 3x, avoid nil returning to IIIF Manifest gem
# @see https://github.com/samvera/iiif_manifest/blob/c408f90eba11bef908796c7236ba6bcf8d687acc/lib/iiif_manifest/v3/manifest_builder/record_property_builder.rb#L28
##
# @return [Array<Hash{String => String}>]
Expand All @@ -25,5 +29,101 @@ def sequence_rendering
'label' => I18n.t("hyrax.manifest.download_text") + (rendering.label || '') }
end.flatten
end

# OVERRIDE: Hyrax v3.x
module DisplayImagePresenterBehavior
ShanaLMoore marked this conversation as resolved.
Show resolved Hide resolved
# Extending the presenter to the base url which includes the protocol.
# We need the base url to render the facet links and normalize the interface.
attr_accessor :base_url

# Extending this class because there is an #ability= but not #ability and this definition
# mirrors the Hyrax::IiifManifestPresenter#ability.
def ability
@ability ||= NullAbility.new
end

def display_image
return nil unless latest_file_id
return nil unless model.image?
return nil unless IiifPrint.config.default_iiif_manifest_version == 2

IIIFManifest::DisplayImage
.new(display_image_url(hostname),
format: image_format(alpha_channels),
width: width,
height: height,
iiif_endpoint: iiif_endpoint(latest_file_id, base_url: hostname))
end

# OVERRIDE: IIIF Hyrax AV v0.2 #display_content for prez 3 manifests
def display_content
return nil unless latest_file_id
return super unless model.image?

IIIFManifest::V3::DisplayContent
.new(display_image_url(hostname),
format: image_format(alpha_channels),
width: width,
height: height,
type: 'Image',
iiif_endpoint: iiif_endpoint(latest_file_id, base_url: hostname))
end

def display_image_url(base_url)
if ENV['EXTERNAL_IIIF_URL'].present?
# At the moment we are only concerned about Hyrax's default image url builder
iiif_image_url_builder(url_builder: Hyrax.config.iiif_image_url_builder)
else
super
end
end

def iiif_endpoint(file_id, base_url: request.base_url)
if ENV['EXTERNAL_IIIF_URL'].present?
IIIFManifest::IIIFEndpoint.new(
File.join(ENV['EXTERNAL_IIIF_URL'], file_id),
profile: Hyrax.config.iiif_image_compliance_level_uri
)
else
super
end
end

def hostname
@hostname || 'localhost'
end

##
# @return [Boolean] false
def work?
false
end

private

def latest_file_id
if ENV['EXTERNAL_IIIF_URL'].present?
external_latest_file_id
else
super
end
end

def external_latest_file_id
@latest_file_id ||= digest_sha1
end

def iiif_image_url_builder(url_builder:)
args = [
latest_file_id,
ENV['EXTERNAL_IIIF_URL'],
Hyrax.config.iiif_image_size_default
]
# In Hyrax 3, Hyrax.config.iiif_image_url_builder takes an additional argument
args << image_format(alpha_channels) if url_builder.arity == 4

url_builder.call(*args).gsub(%r{images/}, '')
end
end
end
end
15 changes: 2 additions & 13 deletions lib/iiif_print/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,6 @@ class Engine < ::Rails::Engine
::BlacklightIiifSearch::IiifSearchAnnotation.prepend(IiifPrint::BlacklightIiifSearch::AnnotationDecorator)
Hyrax::Actors::FileSetActor.prepend(IiifPrint::Actors::FileSetActorDecorator)

# Extending the presenter to the base url which includes the protocol.
# We need the base url to render the facet links and normalize the interface.
Hyrax::IiifManifestPresenter.send(:attr_accessor, :base_url)
Hyrax::IiifManifestPresenter::DisplayImagePresenter.send(:attr_accessor, :base_url)
# Extending this class because there is an #ability= but not #ability and this definition
# mirrors the Hyrax::IiifManifestPresenter#ability.
module Hyrax::IiifManifestPresenter::DisplayImagePresenterDecorator
def ability
@ability ||= NullAbility.new
end
end
Hyrax::IiifManifestPresenter::DisplayImagePresenter.prepend(Hyrax::IiifManifestPresenter::DisplayImagePresenterDecorator)

Hyrax.config do |config|
config.callback.set(:after_create_fileset) do |file_set, user|
IiifPrint.config.handle_after_create_fileset(file_set, user)
Expand All @@ -71,6 +58,8 @@ def ability

config.after_initialize do
IiifPrint::Solr::Document.decorate(SolrDocument)
Hyrax::IiifManifestPresenter::DisplayImagePresenter
.prepend(IiifPrint::IiifManifestPresenterBehavior::DisplayImagePresenterBehavior)
end
# rubocop:enable Metrics/BlockLength
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,55 @@
expect(presenter.search_service).to include("#{solr_document.id}/iiif_search")
end
end

context 'with IIIF external support' do
let(:presenter) { Hyrax::IiifManifestPresenter::DisplayImagePresenter.new(solr_document) }
let(:id) { 'abc123' }
let(:url) { 'external_iiif_url' }
let(:iiif_info_url_builder) { ->(file_id, base_url) { "#{base_url}/#{file_id}" } }

before { allow(solr_document).to receive(:image?).and_return(true) }

context 'when external iiif is enabled' do
before do
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with('EXTERNAL_IIIF_URL').and_return(url)
allow(presenter).to receive(:latest_file_id).and_return(id)
end

describe '#display_image' do
it 'renders a external url' do
expect(presenter.display_image.iiif_endpoint.url).to eq "#{url}/#{id}"
expect(presenter.display_image.iiif_endpoint.profile).to eq "http://iiif.io/api/image/2/level2.json"
end
end

describe '#display_content' do
it 'renders a external url' do
expect(presenter.display_content.iiif_endpoint.url).to eq "#{url}/#{id}"
expect(presenter.display_content.iiif_endpoint.profile).to eq "http://iiif.io/api/image/2/level2.json"
end
end
end

context 'when external iiif is not enabled' do
before do
allow(presenter).to receive(:latest_file_id).and_return(id)
allow(Hyrax.config).to receive(:iiif_image_server?).and_return(true)
allow(Hyrax.config).to receive(:iiif_info_url_builder).and_return(iiif_info_url_builder)
end

describe '#display_image' do
it 'does not render a external url' do
expect(presenter.display_image.iiif_endpoint.url).to eq "localhost/#{id}"
end
end

describe '#display_content' do
it 'does not render a external url' do
expect(presenter.display_content.iiif_endpoint.url).to eq "localhost/#{id}"
end
end
end
end
end