From 629e3ea23548057cac697fcc7f8bbad9c41f62d4 Mon Sep 17 00:00:00 2001 From: Trey Pendragon Date: Thu, 3 Aug 2017 03:07:39 -0700 Subject: [PATCH] Add range support to manifest. (#39) * Add range support to manifest. * Add viewing_hint support. --- .rubocop.yml | 1 + Gemfile | 2 +- Gemfile.lock | 13 +++- .../scanned_resource_change_set.rb | 2 +- app/services/manifest_builder.rb | 74 ++++++++++++++++--- spec/services/manifest_builder_spec.rb | 35 +++++++++ 6 files changed, 111 insertions(+), 16 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 80045a996d..b864cf8ebc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -35,6 +35,7 @@ Metrics/MethodLength: Exclude: - 'db/migrate/**/*' - 'app/models/plum_schema.rb' + - 'spec/services/manifest_builder_spec.rb' Metrics/ModuleLength: Exclude: - 'app/models/plum_schema.rb' diff --git a/Gemfile b/Gemfile index 7750dbdda1..07ff46f126 100644 --- a/Gemfile +++ b/Gemfile @@ -60,7 +60,7 @@ gem 'browse-everything' gem 'coffee-rails' gem 'devise' gem 'hydra-head' -gem 'iiif_manifest' +gem 'iiif_manifest', github: "samvera-labs/iiif_manifest" gem 'modernizr-rails' gem 'normalize-rails' gem 'omniauth-cas' diff --git a/Gemfile.lock b/Gemfile.lock index f5eacb0895..b878c122fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,6 +16,14 @@ GIT specs: pul_uv_rails (2.0.1) +GIT + remote: git://github.com/samvera-labs/iiif_manifest.git + revision: 35f2f17d80034aab13431b7f6350e612fb1db020 + specs: + iiif_manifest (0.2.0) + activesupport (>= 4) + iiif-presentation (~> 0.2.0) + GIT remote: https://github.com/cbeer/devise-guests.git revision: 0999e0bf31841640ad52331e8db14c3f0e1c9765 @@ -350,9 +358,6 @@ GEM activesupport (>= 3.2.18) faraday (>= 0.9) json - iiif_manifest (0.2.0) - activesupport (>= 4) - iiif-presentation (~> 0.2.0) inflecto (0.0.2) jmespath (1.3.1) jquery-rails (4.3.1) @@ -694,7 +699,7 @@ DEPENDENCIES formulaic honeybadger hydra-head - iiif_manifest + iiif_manifest! jquery-rails jquery-ui-rails listen diff --git a/app/change_sets/scanned_resource_change_set.rb b/app/change_sets/scanned_resource_change_set.rb index 4aee5fde5f..7c5c789ebd 100644 --- a/app/change_sets/scanned_resource_change_set.rb +++ b/app/change_sets/scanned_resource_change_set.rb @@ -5,7 +5,7 @@ class ScannedResourceChangeSet < Valkyrie::ChangeSet property :source_metadata_identifier, required: true, multiple: false property :rights_statement, multiple: false, required: true property :rights_note, multiple: false, required: false - property :viewing_hint, multiple: false, required: false + property :viewing_hint, multiple: false, required: false, default: "individuals" property :pdf_type, multiple: false, required: false property :holding_location, multiple: false, required: false property :viewing_direction, multiple: false, required: false diff --git a/app/services/manifest_builder.rb b/app/services/manifest_builder.rb index 093c9fa083..49194e6005 100644 --- a/app/services/manifest_builder.rb +++ b/app/services/manifest_builder.rb @@ -32,24 +32,74 @@ def file_set_presenters end end + def ranges + logical_structure.map do |top_structure| + TopStructure.new(top_structure) + end + end + def manifest_url helper.polymorphic_url([:manifest, resource]) end - def helper - @helper ||= ManifestHelper.new + def viewing_hint + Array(resource.viewing_hint).first + end + + private + + def helper + @helper ||= ManifestHelper.new + end + + def members + @members ||= query_service.find_members(resource: resource).to_a + end + + def leaf_nodes + @leaf_nodes ||= members.select { |x| x.instance_of?(FileSet) } + end + + def metadata_adapter + Valkyrie.config.metadata_adapter + end + + def logical_structure + resource.logical_structure || [] + end + end + + class TopStructure + attr_reader :structure + def initialize(structure) + @structure = structure + end + + def label + structure.label.to_sentence end - def members - @members ||= query_service.find_members(resource: resource).to_a + def ranges + @ranges ||= structure.nodes.select { |x| x.proxy.blank? }.map do |node| + TopStructure.new(node) + end + end + + def file_set_presenters + @file_set_presenters ||= structure.nodes.select { |x| x.proxy.present? }.map do |node| + LeafStructureNode.new(node) + end end + end - def leaf_nodes - @leaf_nodes ||= members.select { |x| x.instance_of?(FileSet) } + class LeafStructureNode + attr_reader :structure + def initialize(structure) + @structure = structure end - def metadata_adapter - Valkyrie.config.metadata_adapter + def id + structure.proxy.first.to_s end end @@ -60,12 +110,16 @@ def initialize(resource) @resource = resource end - delegate :id, to: :derivative_metadata_node + delegate :id, to: :resource def to_s resource.decorate.header end + def derivative_id + derivative_metadata_node.id + end + def display_image IIIFManifest::DisplayImage.new(id, width: width, @@ -97,7 +151,7 @@ def members end def endpoint - IIIFManifest::IIIFEndpoint.new(helper.manifest_image_path(id), + IIIFManifest::IIIFEndpoint.new(helper.manifest_image_path(derivative_id), profile: "http://iiif.io/api/image/2/level2.json") end diff --git a/spec/services/manifest_builder_spec.rb b/spec/services/manifest_builder_spec.rb index d8bba3ab95..42715d987d 100644 --- a/spec/services/manifest_builder_spec.rb +++ b/spec/services/manifest_builder_spec.rb @@ -6,19 +6,54 @@ subject(:manifest_builder) { described_class.new(query_service.find_by(id: scanned_resource.id)) } let(:scanned_resource) { FactoryGirl.create_for_repository(:scanned_resource) } let(:change_set) { ScannedResourceChangeSet.new(scanned_resource, files: [file]) } + let(:logical_structure) do + end let(:change_set_persister) { PlumChangeSetPersister.new(metadata_adapter: metadata_adapter, storage_adapter: Valkyrie.config.storage_adapter) } let(:metadata_adapter) { Valkyrie.config.metadata_adapter } let(:query_service) { metadata_adapter.query_service } let(:file) { fixture_file_upload('files/example.tif', 'image/tiff') } + + def logical_structure(file_set_id) + [ + { + "label": "Table of Contents", + "nodes": [ + { + "label": "Chapter 1", + "nodes": [ + { + "label": "Chapter 1a", + "nodes": [ + { + "proxy": file_set_id + } + ] + } + ] + } + ] + }.deep_symbolize_keys + ] + end describe "#build" do before do + output = change_set_persister.save(change_set: change_set) + file_set_id = output.member_ids.first + change_set = ScannedResourceChangeSet.new(output) + change_set.validate(logical_structure: logical_structure(file_set_id)) + change_set.sync change_set_persister.save(change_set: change_set) end it "generates a IIIF document" do output = manifest_builder.build expect(output).to be_kind_of Hash + expect(output["viewingHint"]).to eq "individuals" expect(output["sequences"].length).to eq 1 + canvas_id = output["sequences"][0]["canvases"][0]["@id"] + expect(output["structures"].length).to eq 3 + structure_canvas_id = output["structures"][2]["canvases"][0] + expect(canvas_id).to eq structure_canvas_id end end end