iiif_print 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Gemfile.lock +2 -2
  4. data/README.md +4 -0
  5. data/app/actors/iiif_print/actors/file_set_actor_decorator.rb +1 -1
  6. data/app/indexers/concerns/iiif_print/child_work_indexer.rb +27 -0
  7. data/app/indexers/concerns/iiif_print/file_set_indexer.rb +37 -22
  8. data/{lib → app/jobs}/iiif_print/jobs/application_job.rb +2 -1
  9. data/{lib → app/jobs}/iiif_print/jobs/child_works_from_pdf_job.rb +14 -9
  10. data/{lib → app/jobs}/iiif_print/jobs/create_relationships_job.rb +10 -20
  11. data/app/listeners/iiif_print/listener.rb +31 -0
  12. data/app/models/concerns/iiif_print/set_child_flag.rb +1 -1
  13. data/app/models/concerns/iiif_print/solr/document.rb +5 -3
  14. data/app/presenters/iiif_print/file_set_presenter_decorator.rb +11 -0
  15. data/app/presenters/iiif_print/iiif_manifest_presenter_factory_behavior.rb +1 -1
  16. data/app/presenters/iiif_print/work_show_presenter_decorator.rb +5 -2
  17. data/app/services/iiif_print/manifest_builder_service_behavior.rb +4 -2
  18. data/app/services/iiif_print/pluggable_derivative_service.rb +5 -1
  19. data/app/services/iiif_print/simple_schema_loader_decorator.rb +11 -0
  20. data/app/transactions/hyrax/transactions/iiif_print_container_decorator.rb +34 -0
  21. data/app/transactions/hyrax/transactions/steps/conditionally_destroy_children_from_split.rb +32 -0
  22. data/app/transactions/hyrax/transactions/steps/delete_all_file_sets_decorator.rb +35 -0
  23. data/app/views/hyrax/file_sets/_show_actions.html.erb +1 -1
  24. data/config/initializers/simple_schema_loader.rb +1 -0
  25. data/config/metadata/child_works_from_pdf_splitting.yaml +21 -0
  26. data/db/migrate/20181214181358_create_iiif_print_derivative_attachments.rb +8 -6
  27. data/db/migrate/20190107165909_create_iiif_print_ingest_file_relations.rb +7 -5
  28. data/db/migrate/20230109000000_create_iiif_print_pending_relationships.rb +8 -6
  29. data/db/migrate/20231110163052_add_model_details_to_iiif_print_pending_relationships.rb +3 -3
  30. data/iiif_print.gemspec +1 -1
  31. data/lib/iiif_print/base_derivative_service.rb +13 -2
  32. data/lib/iiif_print/blacklight_iiif_search/annotation_decorator.rb +2 -2
  33. data/lib/iiif_print/catalog_search_builder.rb +2 -2
  34. data/lib/iiif_print/configuration.rb +65 -5
  35. data/lib/iiif_print/data/fileset_helper.rb +2 -2
  36. data/lib/iiif_print/data/work_derivatives.rb +1 -1
  37. data/lib/iiif_print/engine.rb +46 -2
  38. data/lib/iiif_print/homepage_search_builder.rb +2 -2
  39. data/lib/iiif_print/jp2_derivative_service.rb +4 -1
  40. data/lib/iiif_print/lineage_service.rb +19 -6
  41. data/lib/iiif_print/pdf_derivative_service.rb +3 -1
  42. data/lib/iiif_print/persistence_layer/active_fedora_adapter.rb +189 -0
  43. data/lib/iiif_print/persistence_layer/valkyrie_adapter.rb +183 -0
  44. data/lib/iiif_print/persistence_layer.rb +118 -0
  45. data/lib/iiif_print/split_pdfs/base_splitter.rb +11 -0
  46. data/lib/iiif_print/split_pdfs/child_work_creation_from_pdf_service.rb +19 -9
  47. data/lib/iiif_print/split_pdfs/destroy_pdf_child_works_service.rb +5 -16
  48. data/lib/iiif_print/text_extraction_derivative_service.rb +4 -2
  49. data/lib/iiif_print/text_formats_from_alto_service.rb +3 -1
  50. data/lib/iiif_print/tiff_derivative_service.rb +3 -1
  51. data/lib/iiif_print/version.rb +1 -1
  52. data/lib/iiif_print.rb +79 -44
  53. metadata +18 -191
  54. data/app/indexers/concerns/iiif_print/child_indexer.rb +0 -40
  55. data/app/views/hyrax/file_sets/_actions.html.erb +0 -46
  56. data/bin/rails +0 -13
  57. data/spec/.keep.txt +0 -1
  58. data/spec/factories/ability.rb +0 -6
  59. data/spec/factories/newspaper_issue.rb +0 -7
  60. data/spec/factories/newspaper_page.rb +0 -7
  61. data/spec/factories/newspaper_page_solr_document.rb +0 -20
  62. data/spec/factories/newspaper_title.rb +0 -8
  63. data/spec/factories/uploaded_pdf_file.rb +0 -9
  64. data/spec/factories/uploaded_txt_file.rb +0 -9
  65. data/spec/factories/user.rb +0 -13
  66. data/spec/fixtures/authorities/licenses.yml +0 -4
  67. data/spec/fixtures/authorities/rights_statements.yml +0 -4
  68. data/spec/fixtures/files/4.1.07.jp2 +0 -0
  69. data/spec/fixtures/files/4.1.07.tiff +0 -0
  70. data/spec/fixtures/files/README.md +0 -7
  71. data/spec/fixtures/files/alto-2-0.xsd +0 -714
  72. data/spec/fixtures/files/broken-truncated.pdf +0 -0
  73. data/spec/fixtures/files/credits.md +0 -16
  74. data/spec/fixtures/files/lowres-gray-via-ndnp-sample.tiff +0 -0
  75. data/spec/fixtures/files/minimal-1-page.pdf +0 -0
  76. data/spec/fixtures/files/minimal-2-page.pdf +0 -0
  77. data/spec/fixtures/files/minimal-alto.xml +0 -31
  78. data/spec/fixtures/files/ndnp-alto-sample.xml +0 -24
  79. data/spec/fixtures/files/ndnp-sample1-json.json +0 -1
  80. data/spec/fixtures/files/ndnp-sample1-txt.txt +0 -1
  81. data/spec/fixtures/files/ndnp-sample1.pdf +0 -0
  82. data/spec/fixtures/files/ocr_alto.xml +0 -202
  83. data/spec/fixtures/files/ocr_alto_scaled_4pts_per_px.xml +0 -202
  84. data/spec/fixtures/files/ocr_color.tiff +0 -0
  85. data/spec/fixtures/files/ocr_gray.jp2 +0 -0
  86. data/spec/fixtures/files/ocr_gray.tiff +0 -0
  87. data/spec/fixtures/files/ocr_mono.tiff +0 -0
  88. data/spec/fixtures/files/ocr_mono_text_hocr.html +0 -78
  89. data/spec/fixtures/files/page1.tiff +0 -0
  90. data/spec/fixtures/files/sample-4page-issue.pdf +0 -0
  91. data/spec/fixtures/files/sample-color-newsletter.pdf +0 -0
  92. data/spec/fixtures/files/thumbnail.jpg +0 -0
  93. data/spec/helpers/hyrax/iiif_helper_spec.rb +0 -65
  94. data/spec/helpers/iiif_print_helper_spec.rb +0 -43
  95. data/spec/iiif_print/base_derivative_service_spec.rb +0 -28
  96. data/spec/iiif_print/blacklight_iiif_search/annotation_decorator_spec.rb +0 -59
  97. data/spec/iiif_print/catalog_search_builder_spec.rb +0 -60
  98. data/spec/iiif_print/configuration_spec.rb +0 -193
  99. data/spec/iiif_print/data/work_derivatives_spec.rb +0 -245
  100. data/spec/iiif_print/data/work_file_spec.rb +0 -99
  101. data/spec/iiif_print/data/work_files_spec.rb +0 -237
  102. data/spec/iiif_print/image_tool_spec.rb +0 -109
  103. data/spec/iiif_print/jobs/child_works_from_pdf_job_spec.rb +0 -35
  104. data/spec/iiif_print/jobs/create_relationships_job_spec.rb +0 -118
  105. data/spec/iiif_print/jp2_image_metadata_spec.rb +0 -37
  106. data/spec/iiif_print/lineage_service_spec.rb +0 -13
  107. data/spec/iiif_print/metadata_spec.rb +0 -249
  108. data/spec/iiif_print/split_pdfs/base_splitter_spec.rb +0 -27
  109. data/spec/iiif_print/split_pdfs/derivative_rodeo_splitter_spec.rb +0 -80
  110. data/spec/iiif_print/split_pdfs/destroy_pdf_child_works_service_spec.rb +0 -92
  111. data/spec/iiif_print/split_pdfs/pages_to_jpgs_splitter_spec.rb +0 -22
  112. data/spec/iiif_print/split_pdfs/pages_to_pngs_splitter_spec.rb +0 -18
  113. data/spec/iiif_print/split_pdfs/pages_to_tiffs_splitter_spec.rb +0 -19
  114. data/spec/iiif_print/text_extraction/alto_reader_spec.rb +0 -49
  115. data/spec/iiif_print/text_extraction/hocr_reader_spec.rb +0 -45
  116. data/spec/iiif_print/text_extraction/page_ocr_spec.rb +0 -84
  117. data/spec/iiif_print/text_extraction/render_alto_spec.rb +0 -54
  118. data/spec/iiif_print/text_extraction/word_coords_builder_spec.rb +0 -44
  119. data/spec/iiif_print_spec.rb +0 -171
  120. data/spec/misc_shared.rb +0 -111
  121. data/spec/models/iiif_print/derivative_attachment_spec.rb +0 -37
  122. data/spec/models/iiif_print/iiif_search_decorator_spec.rb +0 -27
  123. data/spec/models/iiif_print/ingest_file_relation_spec.rb +0 -56
  124. data/spec/models/solr_document_spec.rb +0 -14
  125. data/spec/presenters/iiif_print/iiif_manifest_presenter_behavior_spec.rb +0 -70
  126. data/spec/presenters/iiif_print/iiif_manifest_presenter_factory_behavior_spec.rb +0 -49
  127. data/spec/samvera/derivatives/configuration_spec.rb +0 -41
  128. data/spec/samvera/derivatives/hyrax_spec.rb +0 -62
  129. data/spec/samvera/derivatives_spec.rb +0 -54
  130. data/spec/services/iiif_print/derivative_rodeo_service_spec.rb +0 -103
  131. data/spec/services/iiif_print/jp2_derivative_service_spec.rb +0 -59
  132. data/spec/services/iiif_print/manifest_builder_service_behavior_spec.rb +0 -20
  133. data/spec/services/iiif_print/pdf_derivative_service_spec.rb +0 -66
  134. data/spec/services/iiif_print/pluggable_derivative_service_spec.rb +0 -175
  135. data/spec/services/iiif_print/text_extraction_derivative_service_spec.rb +0 -82
  136. data/spec/services/iiif_print/text_formats_from_alto_service_spec.rb +0 -127
  137. data/spec/services/iiif_print/tiff_derivative_service_spec.rb +0 -65
  138. data/spec/spec_helper.rb +0 -181
  139. data/spec/support/controller_level_helpers.rb +0 -28
  140. data/spec/support/iiif_print_models.rb +0 -127
  141. data/spec/test_app_templates/blacklight.yml +0 -9
  142. data/spec/test_app_templates/fedora.yml +0 -15
  143. data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -40
  144. data/spec/test_app_templates/redis.yml +0 -9
  145. data/spec/test_app_templates/solr/conf/schema.xml +0 -362
  146. data/spec/test_app_templates/solr/conf/solrconfig.xml +0 -322
  147. data/spec/test_app_templates/solr.yml +0 -7
  148. /data/{lib → app/jobs}/iiif_print/jobs/request_split_pdf_job.rb +0 -0
@@ -1,11 +1,13 @@
1
1
  class CreateIiifPrintIngestFileRelations < ActiveRecord::Migration[5.0]
2
2
  def change
3
- create_table :iiif_print_ingest_file_relations do |t|
4
- t.string :file_path
5
- t.string :derivative_path
3
+ unless table_exists?(:iiif_print_ingest_file_relations)
4
+ create_table :iiif_print_ingest_file_relations do |t|
5
+ t.string :file_path
6
+ t.string :derivative_path
6
7
 
7
- t.timestamps
8
+ t.timestamps
9
+ end
10
+ add_index :iiif_print_ingest_file_relations, :file_path
8
11
  end
9
- add_index :iiif_print_ingest_file_relations, :file_path
10
12
  end
11
13
  end
@@ -1,11 +1,13 @@
1
1
  class CreateIiifPrintPendingRelationships < ActiveRecord::Migration[5.1]
2
2
  def change
3
- create_table :iiif_print_pending_relationships do |t|
4
- t.string :child_title, null: false
5
- t.string :parent_id, null: false
6
- t.string :child_order, null: false
7
- t.timestamps
3
+ unless table_exists?(:iiif_print_pending_relationships)
4
+ create_table :iiif_print_pending_relationships do |t|
5
+ t.string :child_title, null: false
6
+ t.string :parent_id, null: false
7
+ t.string :child_order, null: false
8
+ t.timestamps
9
+ end
10
+ add_index :iiif_print_pending_relationships, :parent_id
8
11
  end
9
- add_index :iiif_print_pending_relationships, :parent_id
10
12
  end
11
13
  end
@@ -1,7 +1,7 @@
1
1
  class AddModelDetailsToIiifPrintPendingRelationships < ActiveRecord::Migration[5.2]
2
2
  def change
3
- add_column :iiif_print_pending_relationships, :parent_model, :string
4
- add_column :iiif_print_pending_relationships, :child_model, :string
5
- add_column :iiif_print_pending_relationships, :file_id, :string
3
+ add_column :iiif_print_pending_relationships, :parent_model, :string unless column_exists?(:iiif_print_pending_relationships, :parent_model)
4
+ add_column :iiif_print_pending_relationships, :child_model, :string unless column_exists?(:iiif_print_pending_relationships, :child_model)
5
+ add_column :iiif_print_pending_relationships, :file_id, :string unless column_exists?(:iiif_print_pending_relationships, :file_id)
6
6
  end
7
7
  end
data/iiif_print.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  IiifPrint is a gem (Rails "engine") for Hyrax-based digital repository applications to support displaying parent/child works in the same viewer (Universal Viewer) and the ability to search OCR from the parent work to the child work(s). IiifPring was originally based off of the samvera-labs Newspaper gem.
19
19
  SUMMARY
20
20
  spec.license = 'Apache-2.0'
21
- spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
21
+ spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR).select { |f| File.dirname(f) !~ %r{\A"?spec\/?} && f != 'bin/rails' }
22
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
23
  spec.add_dependency 'blacklight_iiif_search', '>= 1.0', '< 3.0'
24
24
  spec.add_dependency 'derivative-rodeo', "~> 0.5"
@@ -7,7 +7,11 @@ module IiifPrint
7
7
  class_attribute :target_extension, default: nil
8
8
 
9
9
  def initialize(file_set)
10
- @file_set = file_set
10
+ @file_set = if file_set.is_a?(Hyrax::FileMetadata)
11
+ Hyrax.query_service.find_by(id: file_set.file_set_id)
12
+ else
13
+ file_set
14
+ end
11
15
  @dest_path = nil
12
16
  @source_path = nil
13
17
  @source_meta = nil
@@ -26,7 +30,10 @@ module IiifPrint
26
30
  # @return [Boolean]
27
31
  def valid?
28
32
  # @note We are taking a shortcut because currently we are only concerned about images.
29
- file_set.class.image_mime_types.include?(file_set.mime_type)
33
+ # @TODO: verify if this works for ActiveFedora and if so, remove commented code.
34
+ # If not, modify to use adapter.
35
+ # file_set.class.image_mime_types.include?(file_set.mime_type)
36
+ file_set.original_file.image?
30
37
  end
31
38
 
32
39
  def derivative_path_factory
@@ -110,5 +117,9 @@ module IiifPrint
110
117
  # intermediate -> PDF
111
118
  im_convert
112
119
  end
120
+
121
+ def mime_type_for(extension)
122
+ Marcel::MimeType.for extension: extension
123
+ end
113
124
  end
114
125
  end
@@ -103,10 +103,10 @@ module IiifPrint
103
103
  def file_set_id
104
104
  return document['id'] if document.file_set?
105
105
 
106
- file_set_ids = document['file_set_ids_ssim']
106
+ file_set_ids = document['member_ids_ssim']
107
107
  raise "#{self.class}: NO FILE SET ID" if file_set_ids.blank?
108
108
 
109
- # Since a parent work's `file_set_ids_ssim` can contain child work ids as well as file set ids,
109
+ # Since a parent work's `member_ids_ssim` can contain child work ids as well as file set ids,
110
110
  # this will ensure that the file set id is indeed a `FileSet`
111
111
  file_set_ids.detect { |id| SolrDocument.find(id).file_set? }
112
112
  end
@@ -25,9 +25,9 @@ module IiifPrint
25
25
  # rubocop:enable Naming/PredicateName
26
26
  def show_parents_only(solr_parameters)
27
27
  query = if blacklight_params["include_child_works"] == 'true'
28
- ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: 'true')
28
+ IiifPrint.solr_construct_query(is_child_bsi: 'true')
29
29
  else
30
- ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: nil)
30
+ IiifPrint.solr_construct_query(is_child_bsi: nil)
31
31
  end
32
32
  solr_parameters[:fq] += [query]
33
33
  end
@@ -3,6 +3,36 @@ module IiifPrint
3
3
  class Configuration
4
4
  attr_writer :after_create_fileset_handler
5
5
 
6
+ attr_writer :ingest_queue_name
7
+ ##
8
+ # @return [Symbol, Proc]
9
+ def ingest_queue_name
10
+ return @ingest_queue_name if @ingest_queue_name.present?
11
+ if defined?(Hyrax)
12
+ Hyrax.config.ingest_queue_name
13
+ elsif defined?(Bulkrax) && Bulkrax.config.respond_to?(:ingest_queue_name)
14
+ Bulkrax.config.ingest_queue_name
15
+ else
16
+ :ingest
17
+ end
18
+ end
19
+
20
+ attr_writer :persistence_adapter
21
+ def persistence_adapter
22
+ @persistence_adapter || default_persistence_adapter
23
+ end
24
+
25
+ def default_persistence_adapter
26
+ # There's probably some configuration of Hyrax we could use to better refine this; but it's
27
+ # likely a reasonable guess. The main goal is to not break existing implementations and
28
+ # maintain an upgrade path.
29
+ if Gem::Version.new(Hyrax::VERSION) >= Gem::Version.new('6.0.0')
30
+ IiifPrint::PersistenceLayer::ValkyrieAdapter
31
+ else
32
+ IiifPrint::PersistenceLayer::ActiveFedoraAdapter
33
+ end
34
+ end
35
+
6
36
  # @param file_set [FileSet]
7
37
  # @param user [User]
8
38
  def handle_after_create_fileset(file_set, user)
@@ -14,11 +44,14 @@ module IiifPrint
14
44
  end
15
45
 
16
46
  attr_writer :ancestory_identifier_function
17
- # The function, with arity 1, that receives a work and returns it's identifier for the purposes
18
- # of object ancestry.
47
+ # The function, with arity 1, that receives a work and returns it's identifier (as a string) for
48
+ # the purposes of object ancestry.
49
+ #
19
50
  # @return [Proc]
20
51
  def ancestory_identifier_function
21
- @ancestory_identifier_function ||= ->(work) { work.id }
52
+ # If the work.id is nil, keep it nil. Otherwise cast that id to a string; to deal with the
53
+ # `Valkyrie::ID`.
54
+ @ancestory_identifier_function ||= ->(work) { work.id&.to_s }
22
55
  end
23
56
 
24
57
  attr_writer :excluded_model_name_solr_field_values
@@ -158,17 +191,44 @@ module IiifPrint
158
191
  attr_writer :child_work_attributes_function
159
192
  ##
160
193
  # Here we allow for customization of the child work attributes
194
+ # rubocop:disable Metrics/MethodLength, Metrics/BlockLength
161
195
  def child_work_attributes_function
162
196
  @child_work_attributes_function ||= lambda do |parent_work:, admin_set_id:|
163
- {
197
+ embargo = parent_work.embargo
198
+ lease = parent_work.lease
199
+ embargo_params = {}
200
+ lease_params = {}
201
+ visibility_params = {}
202
+
203
+ if embargo
204
+ embargo_params = {
205
+ visibility: 'embargo',
206
+ visibility_after_embargo: embargo.visibility_after_embargo,
207
+ visibility_during_embargo: embargo.visibility_during_embargo,
208
+ embargo_release_date: embargo.embargo_release_date
209
+ }
210
+ elsif lease
211
+ lease_params = {
212
+ visibility: 'lease',
213
+ visibility_after_lease: lease.visibility_after_lease,
214
+ visibility_during_lease: lease.visibility_during_lease,
215
+ lease_release_date: lease.lease_release_date
216
+ }
217
+ else
218
+ visibility_params = { visibility: parent_work.visibility.to_s }
219
+ end
220
+
221
+ params = {
164
222
  admin_set_id: admin_set_id.to_s,
165
223
  creator: parent_work.creator.to_a,
166
224
  rights_statement: parent_work.rights_statement.to_a,
167
- visibility: parent_work.visibility.to_s,
168
225
  is_child: true
169
226
  }
227
+
228
+ params.merge!(embargo_params).merge!(lease_params).merge!(visibility_params)
170
229
  end
171
230
  end
231
+ # rubocop:enable Metrics/MethodLength, Metrics/BlockLength
172
232
 
173
233
  attr_writer :sort_iiif_manifest_canvases_by
174
234
  ##
@@ -15,9 +15,9 @@ module IiifPrint
15
15
  # get the fileset from that id
16
16
  return FileSet.find(@work) if @work.is_a?(String)
17
17
  # if "work" context is a FileSet, not actual work, return it
18
- return @work if @work.is_a? FileSet
18
+ return @work if @work.is_a?(Hyrax::FileSet) || @work.is_a?(FileSet)
19
19
  # in most cases, get from work's members:
20
- filesets = @work.members.select { |m| m.is_a? FileSet }
20
+ filesets = @work.members.select { |m| m.is_a?(Hyrax::FileSet) || m.is_a?(FileSet) }
21
21
  filesets.empty? ? nil : filesets[0]
22
22
  end
23
23
  end
@@ -239,7 +239,7 @@ module IiifPrint
239
239
  # of the first assigned file path for single-file work.
240
240
  work_file = parent
241
241
  return if work_file.nil?
242
- work_files = work_file.parent
242
+ work_files = IiifPrint.parent_for(work_file)
243
243
  return if work_files.nil?
244
244
  work_files.assigned[0]
245
245
  else
@@ -11,6 +11,15 @@ module IiifPrint
11
11
  class Engine < ::Rails::Engine
12
12
  isolate_namespace IiifPrint
13
13
 
14
+ config.eager_load_paths += %W[#{config.root}/app/transactions]
15
+
16
+ initializer 'requires' do
17
+ require 'hyrax/transactions/iiif_print_container_decorator'
18
+ require 'iiif_print/persistence_layer'
19
+ require 'iiif_print/persistence_layer/active_fedora_adapter' if defined?(ActiveFedora)
20
+ require 'iiif_print/persistence_layer/valkyrie_adapter' if defined?(Valkyrie)
21
+ end
22
+
14
23
  # rubocop:disable Metrics/BlockLength
15
24
  config.to_prepare do
16
25
  require "iiif_print/jobs/create_relationships_job"
@@ -37,16 +46,51 @@ module IiifPrint
37
46
  IiifPrint::PluggableDerivativeService
38
47
  )
39
48
 
49
+ Hyrax.publisher.subscribe(IiifPrint::Listener.new) if Hyrax.respond_to?(:publisher)
50
+
40
51
  Hyrax::IiifManifestPresenter.prepend(IiifPrint::IiifManifestPresenterBehavior)
41
52
  Hyrax::IiifManifestPresenter::Factory.prepend(IiifPrint::IiifManifestPresenterFactoryBehavior)
42
53
  Hyrax::ManifestBuilderService.prepend(IiifPrint::ManifestBuilderServiceBehavior)
43
54
  Hyrax::Renderers::FacetedAttributeRenderer.prepend(Hyrax::Renderers::FacetedAttributeRendererDecorator)
44
55
  Hyrax::WorksControllerBehavior.prepend(IiifPrint::WorksControllerBehaviorDecorator)
56
+ "Hyrax::Transactions::Steps::DeleteAllFileSets".safe_constantize&.prepend(Hyrax::Transactions::Steps::DeleteAllFileSetsDecorator)
57
+ # Hyku::WorksControllerBehavior was introduced in Hyku v6.0.0+. Yes we don't depend on Hyku,
58
+ # but this allows us to do minimal Hyku antics with IiifPrint.
59
+ 'Hyku::WorksControllerBehavior'.safe_constantize&.prepend(IiifPrint::WorksControllerBehaviorDecorator)
60
+
61
+ Hyrax::FileSetPresenter.prepend(IiifPrint::FileSetPresenterDecorator)
45
62
  Hyrax::WorkShowPresenter.prepend(IiifPrint::WorkShowPresenterDecorator)
46
63
  Hyrax::IiifHelper.prepend(IiifPrint::IiifHelperDecorator)
47
64
 
48
- IiifPrint::ChildIndexer.decorate_work_types!
49
- IiifPrint::FileSetIndexer.decorate(Hyrax::FileSetIndexer)
65
+ if ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYRAX_VALKYRIE', false))
66
+ # Newer versions of Hyrax favor `Hyrax::Indexers::FileSetIndexer` and deprecate
67
+ # `Hyrax::ValkyrieFileSetIndexer`.
68
+ 'Hyrax::Indexers::FileSetIndexer'.safe_constantize&.prepend(IiifPrint::FileSetIndexer)
69
+
70
+ # Versions 3.0+ of Hyrax have `Hyrax::ValkyrieFileSetIndexer` so we want to decorate that as
71
+ # well. We want to use the elsif construct because later on Hyrax::ValkyrieFileSetIndexer
72
+ # inherits from Hyrax::Indexers::FileSetIndexer and only implements:
73
+ # `def initialize(*args); super; end`
74
+ 'Hyrax::ValkyrieFileSetIndexer'.safe_constantize&.prepend(IiifPrint::FileSetIndexer)
75
+
76
+ # Newer versions of Hyrax favor `Hyrax::Indexers::PcdmObjectIndexer` and deprecate
77
+ # `Hyrax::ValkyrieWorkIndexer`
78
+ indexers = Hyrax.config.curation_concerns.map do |concern|
79
+ "#{concern}ResourceIndexer".safe_constantize
80
+ end
81
+ indexers.each { |indexer| indexer.prepend(IiifPrint::ChildWorkIndexer) }
82
+
83
+ # Versions 3.0+ of Hyrax have `Hyrax::ValkyrieWorkIndexer` so we want to decorate that as
84
+ # well. We want to use the elsif construct because later on Hyrax::ValkyrieWorkIndexer
85
+ # inherits from Hyrax::Indexers::PcdmObjectIndexer and only implements:
86
+ # `def initialize(*args); super; end`
87
+ 'Hyrax::ValkyrieWorkIndexer'.safe_constantize&.prepend(IiifPrint::ChildWorkIndexer)
88
+ else
89
+ # The ActiveFedora::Base indexer for FileSets
90
+ Hyrax::FileSetIndexer.prepend(IiifPrint::FileSetIndexer)
91
+ # The ActiveFedora::Base indexer for Works
92
+ Hyrax::WorkIndexer.prepend(IiifPrint::ChildWorkIndexer)
93
+ end
50
94
 
51
95
  ::BlacklightIiifSearch::IiifSearchResponse.prepend(IiifPrint::IiifSearchResponseDecorator)
52
96
  ::BlacklightIiifSearch::IiifSearchAnnotation.prepend(IiifPrint::BlacklightIiifSearch::AnnotationDecorator)
@@ -7,9 +7,9 @@ module IiifPrint
7
7
 
8
8
  def show_parents_only(solr_parameters)
9
9
  query = if blacklight_params["include_child_works"] == 'true'
10
- ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: 'true')
10
+ IiifPrint.solr_construct_query(is_child_bsi: 'true')
11
11
  else
12
- ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: nil)
12
+ IiifPrint.solr_construct_query(is_child_bsi: nil)
13
13
  end
14
14
  solr_parameters[:fq] += [query]
15
15
  end
@@ -53,7 +53,10 @@ module IiifPrint
53
53
  render_cmd = opj_command
54
54
 
55
55
  # Run the generated command to make derivative file at @dest_path
56
- `#{render_cmd}`
56
+ data = `#{render_cmd}`
57
+
58
+ # Create Hyrax::FileMetadata object for the derivatives (if Valkyrie)
59
+ IiifPrint.copy_derivatives_from_data_store(stream: data, directives: { url: file_set.id.to_s, container: 'service_file', mime_type: mime_type_for(target_extension) })
57
60
 
58
61
  # Clean up any intermediate files or symlinks used during creation
59
62
  cleanup_intermediate
@@ -3,6 +3,7 @@ module IiifPrint
3
3
  #
4
4
  # - {.ancestor_ids_for}
5
5
  # - {.descendent_member_ids_for}
6
+ # - {.ancestor_identifier_for}
6
7
  #
7
8
  # The ancestor and descendent_file_sets are useful for ensuring we index together related items.
8
9
  # For example, when I have a work that is a book, and one file set per page of that book, when I
@@ -15,13 +16,21 @@ module IiifPrint
15
16
  #
16
17
  # @param object [#in_works] An object that responds to #in_works
17
18
  # @return [Array<String>]
19
+ #
20
+ # @note For those implementing their own lineage service, verify that you are not returning
21
+ # an array of
18
22
  def self.ancestor_ids_for(object)
19
23
  ancestor_ids ||= []
20
- object.in_works.each do |work|
24
+ # Yes, we're fetching the works, then compressing those into identifiers. Because in the case
25
+ # of slugs, we need not the identifier, but the slug as the id.
26
+ IiifPrint.object_in_works(object).each do |work|
21
27
  ancestor_ids << ancestry_identifier_for(work)
22
- ancestor_ids += ancestor_ids_for(work) if work.is_child
28
+ ancestor_ids += ancestor_ids_for(work) if work.respond_to?(:is_child) && work.is_child
23
29
  end
24
- ancestor_ids.flatten.compact.uniq
30
+ # We must convert these to strings as Valkyrie's identifiers will be cast to hashes when we
31
+ # attempt to write the SolrDocument. Also, per documentation we return an Array of strings, not
32
+ # an Array that might include Valkyrie::ID objects.
33
+ ancestor_ids.flatten.compact.uniq.map(&:to_s)
25
34
  end
26
35
 
27
36
  ##
@@ -43,6 +52,8 @@ module IiifPrint
43
52
  # https://github.com/samvera/hyrax/blob/2b807fe101176d594129ef8a8fe466d3d03a372b/app/indexers/hyrax/work_indexer.rb#L15-L18
44
53
  # for "clarification" of the comingling of file_set_ids and member_ids
45
54
  def self.descendent_member_ids_for(object)
55
+ return unless object.respond_to?(:member_ids)
56
+
46
57
  # enables us to return parents when searching for child OCR
47
58
  #
48
59
  # https://github.com/samvera/hydra-works/blob/c9b9dd0cf11de671920ba0a7161db68ccf9b7f6d/lib/hydra/works/models/concerns/work_behavior.rb#L90-L92
@@ -50,10 +61,12 @@ module IiifPrint
50
61
  # The Hydara::Works implementation of file_set_ids is "members.select(&:file_set?).map(&:id)";
51
62
  # so no sense doing `object.file_set_ids + object.member_ids`
52
63
  file_set_ids = object.member_ids
53
- object.ordered_works&.each do |child|
54
- file_set_ids += descendent_member_ids_for(child)
64
+ IiifPrint.object_ordered_works(object)&.each do |child|
65
+ file_set_ids += Array.wrap(descendent_member_ids_for(child))
55
66
  end
56
- file_set_ids.flatten.uniq.compact
67
+ # We must convert these to strings as Valkyrie's identifiers will be cast to hashes when we
68
+ # attempt to write the SolrDocument.
69
+ file_set_ids.flatten.uniq.compact.map(&:to_s)
57
70
  end
58
71
  class << self
59
72
  alias descendent_file_set_ids_for descendent_member_ids_for
@@ -24,7 +24,9 @@ module IiifPrint
24
24
  # JP2 source, and whether we have color or grayscale material.
25
25
  def convert_cmd
26
26
  template = use_color? ? COLOR_PDF_CMD : GRAY_PDF_CMD
27
- format(template, source_file: @source_path, out_file: @dest_path)
27
+ data = format(template, source_file: @source_path, out_file: @dest_path)
28
+ IiifPrint.copy_derivatives_from_data_store(stream: data, directives: { url: file_set.id.to_s, container: 'service_file', mime_type: mime_type_for(target_extension) })
29
+ data
28
30
  end
29
31
 
30
32
  def create_derivatives(filename)
@@ -0,0 +1,189 @@
1
+ module IiifPrint
2
+ module PersistenceLayer
3
+ class ActiveFedoraAdapter < AbstractAdapter
4
+ ##
5
+ # @param object [ActiveFedora::Base]
6
+ # @return [Array<SolrDocument>]
7
+ def self.object_in_works(object)
8
+ object.in_works
9
+ end
10
+
11
+ ##
12
+ # @param object [ActiveFedora::Base]
13
+ # @return [Array<SolrDocument>]
14
+ def self.object_ordered_works(object)
15
+ object.ordered_works
16
+ end
17
+
18
+ ##
19
+ # @param work_type [Class<ActiveFedora::Base>]
20
+ # @return indexer for the given :work_type
21
+ def self.decorate_with_adapter_logic(work_type:)
22
+ work_type.send(:include, IiifPrint::SetChildFlag) unless work_type.included_modules.include?(IiifPrint::SetChildFlag)
23
+ work_type.indexer
24
+ end
25
+
26
+ ##
27
+ # @param work_type [Class<ActiveFedora::Base>]
28
+ # @return indexer for the given :work_type
29
+ def self.decorate_form_with_adapter_logic(work_type:)
30
+ work_type.indexer
31
+ end
32
+
33
+ ##
34
+ # Return the immediate parent of the given :file_set.
35
+ #
36
+ # @param file_set [FileSet]
37
+ # @return [#work?, Hydra::PCDM::Work]
38
+ # @return [NilClass] when no parent is found.
39
+ def self.parent_for(file_set)
40
+ # fallback to Fedora-stored relationships if work's aggregation of
41
+ # file set is not indexed in Solr
42
+ file_set.parent || file_set.member_of.find(&:work?)
43
+ end
44
+
45
+ ##
46
+ # Return the parent's parent of the given :file_set.
47
+ #
48
+ # @param file_set [FileSet]
49
+ # @return [#work?, Hydra::PCDM::Work]
50
+ # @return [NilClass] when no grand parent is found.
51
+ def self.grandparent_for(file_set)
52
+ parent_of_file_set = parent_for(file_set)
53
+ # HACK: This is an assumption about the file_set structure, namely that an image page split from
54
+ # a PDF is part of a file set that is a child of a work that is a child of a single work. That
55
+ # is, it only has one grand parent. Which is a reasonable assumption for IIIF Print but is not
56
+ # valid when extended beyond IIIF Print. That is GenericWork does not have a parent method but
57
+ # does have a parents method.
58
+ parent_of_file_set.try(:parent_works).try(:first) ||
59
+ parent_of_file_set.try(:parents).try(:first) ||
60
+ parent_of_file_set&.member_of&.find(&:work?)
61
+ end
62
+
63
+ def self.solr_construct_query(*args)
64
+ if defined?(Hyrax::SolrQueryBuilderService)
65
+ Hyrax::SolrQueryBuilderService.construct_query(*args)
66
+ else
67
+ ActiveFedora::SolrQueryBuilder.construct_query(*args)
68
+ end
69
+ end
70
+
71
+ def self.clean_for_tests!
72
+ super do
73
+ ActiveFedora::Cleaner.clean!
74
+ end
75
+ end
76
+
77
+ def self.solr_query(query, **args)
78
+ if defined?(ActiveFedora::SolrService)
79
+ ActiveFedora::SolrService.query(query, **args)
80
+ else
81
+ Hyrax::SolrService.query(query, **args)
82
+ end
83
+ end
84
+
85
+ def self.solr_name(field_name)
86
+ if defined?(Hyrax) && Hyrax.config.respond_to?(:index_field_mapper)
87
+ Hyrax.config.index_field_mapper.solr_name(field_name.to_s)
88
+ else
89
+ ::ActiveFedora.index_field_mapper.solr_name(field_name.to_s)
90
+ end
91
+ end
92
+
93
+ ##
94
+ # @param file_set [Object]
95
+ # @param work [Object]
96
+ # @param model [Class] The class name for which we'll split children.
97
+ def self.destroy_children_split_from(file_set:, work:, model:, **_args)
98
+ # look first for children by the file set id they were split from
99
+ children = model.where(split_from_pdf_id: file_set.id)
100
+ if children.blank?
101
+ # find works where file name and work `to_param` are both in the title
102
+ children = model.where(title: file_set.label).where(title: work.to_param)
103
+ end
104
+ return if children.blank?
105
+ children.each do |rcd|
106
+ rcd.destroy(eradicate: true)
107
+ end
108
+ true
109
+ end
110
+
111
+ def self.pdf?(file_set)
112
+ file_set.class.pdf_mime_types.include?(file_set.mime_type)
113
+ end
114
+
115
+ ##
116
+ # Add a child record as a member of a parent record
117
+ #
118
+ # @param model [child_record] an ActiveFedora::Base model
119
+ # @param model [parent_record] an ActiveFedora::Base model
120
+ # @return [TrueClass]
121
+ def self.create_relationship_between(child_record:, parent_record:)
122
+ return true if parent_record.ordered_members.to_a.include?(child_record)
123
+ parent_record.ordered_members << child_record
124
+ true
125
+ end
126
+
127
+ ##
128
+ # find a work by title
129
+ # We should only find one, but there is no guarantee of that and `:where` returns an array.
130
+ #
131
+ # @param title [String]
132
+ # @param model [String] an ActiveFedora::Base model
133
+ def self.find_by_title_for(title:, model:)
134
+ work_type = model.constantize
135
+
136
+ work_type.where(title: title)
137
+ end
138
+
139
+ ##
140
+ # find a work or file_set
141
+ #
142
+ # @param id [String]
143
+ # @return [Array<ActiveFedora::Base]
144
+ def self.find_by(id:)
145
+ ActiveFedora::Base.find(id)
146
+ end
147
+
148
+ ##
149
+ # save a work
150
+ #
151
+ # @param object [Array<ActiveFedora::Base]
152
+ def self.save(object:)
153
+ object.save!
154
+ end
155
+
156
+ ##
157
+ # reindex an array of works and their file_sets
158
+ #
159
+ # @param objects [Array<ActiveFedora::Base]
160
+ # @return [TrueClass]
161
+ def self.index_works(objects:)
162
+ objects.each do |work|
163
+ work.update_index
164
+ work.file_sets.each(&:update_index) if work.respond_to?(:file_sets)
165
+ end
166
+ true
167
+ end
168
+
169
+ ##
170
+ # does nothing for ActiveFedora;
171
+ # allows valkyrie works to have an extra step to create the Hyrax::Metadata objects.
172
+ #
173
+ # @param []
174
+ # @return [TrueClass]
175
+ def self.copy_derivatives_from_data_store(*)
176
+ true
177
+ end
178
+
179
+ ##
180
+ # Extract text from the derivatives
181
+ #
182
+ # @param [FileSet] an ActiveFedora fileset
183
+ # @return [String] Text from fileset's file
184
+ def self.extract_text_for(file_set:)
185
+ IiifPrint.config.all_text_generator_function.call(object: file_set) || ''
186
+ end
187
+ end
188
+ end
189
+ end