iiif_print 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +18 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  4. data/.github/workflows/build-lint-test-action.yaml +4 -5
  5. data/.gitignore +5 -4
  6. data/.rubocop.yml +1 -0
  7. data/.solargraph.yml +19 -0
  8. data/Gemfile.lock +1025 -0
  9. data/README.md +102 -9
  10. data/Rakefile +6 -0
  11. data/app/actors/iiif_print/actors/cleanup_file_sets_actor_decorator.rb +24 -0
  12. data/app/actors/iiif_print/actors/file_set_actor_decorator.rb +30 -28
  13. data/app/controllers/iiif_print/split_pdfs_controller.rb +38 -0
  14. data/app/helpers/iiif_print/iiif_helper_decorator.rb +32 -0
  15. data/app/helpers/iiif_print/iiif_print_helper_behavior.rb +23 -0
  16. data/app/helpers/iiif_print_helper.rb +0 -20
  17. data/app/indexers/concerns/iiif_print/child_work_indexer.rb +27 -0
  18. data/app/indexers/concerns/iiif_print/file_set_indexer.rb +45 -17
  19. data/{lib → app/jobs}/iiif_print/jobs/application_job.rb +2 -1
  20. data/app/jobs/iiif_print/jobs/child_works_from_pdf_job.rb +153 -0
  21. data/app/jobs/iiif_print/jobs/create_relationships_job.rb +117 -0
  22. data/app/jobs/iiif_print/jobs/request_split_pdf_job.rb +31 -0
  23. data/app/listeners/iiif_print/listener.rb +31 -0
  24. data/app/models/concerns/iiif_print/set_child_flag.rb +10 -1
  25. data/app/models/concerns/iiif_print/solr/document.rb +19 -3
  26. data/app/models/iiif_print/iiif_search_decorator.rb +35 -0
  27. data/app/models/iiif_print/iiif_search_response_decorator.rb +25 -2
  28. data/app/models/iiif_print/pending_relationship.rb +3 -0
  29. data/app/presenters/iiif_print/file_set_presenter_decorator.rb +11 -0
  30. data/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb +120 -0
  31. data/app/presenters/iiif_print/iiif_manifest_presenter_factory_behavior.rb +1 -1
  32. data/app/presenters/iiif_print/work_show_presenter_decorator.rb +23 -11
  33. data/app/search_builders/concerns/iiif_print/allinson_flex_fields.rb +15 -0
  34. data/app/search_builders/concerns/iiif_print/highlight_search_params.rb +2 -1
  35. data/app/services/iiif_print/derivative_rodeo_service.rb +382 -0
  36. data/app/services/iiif_print/manifest_builder_service_behavior.rb +90 -31
  37. data/app/services/iiif_print/pluggable_derivative_service.rb +8 -10
  38. data/app/services/iiif_print/simple_schema_loader_decorator.rb +11 -0
  39. data/app/transactions/hyrax/transactions/iiif_print_container_decorator.rb +34 -0
  40. data/app/transactions/hyrax/transactions/steps/conditionally_destroy_children_from_split.rb +32 -0
  41. data/app/transactions/hyrax/transactions/steps/delete_all_file_sets_decorator.rb +35 -0
  42. data/app/views/catalog/_index_header_list_default.html.erb +13 -0
  43. data/app/views/hyrax/base/_representative_media.html.erb +4 -3
  44. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
  45. data/app/views/hyrax/file_sets/_show_actions.html.erb +24 -0
  46. data/config/initializers/simple_schema_loader.rb +1 -0
  47. data/config/locales/iiif_print.en.yml +4 -0
  48. data/config/metadata/child_works_from_pdf_splitting.yaml +21 -0
  49. data/config/routes.rb +3 -0
  50. data/db/migrate/20181214181358_create_iiif_print_derivative_attachments.rb +8 -6
  51. data/db/migrate/20190107165909_create_iiif_print_ingest_file_relations.rb +7 -5
  52. data/db/migrate/20230109000000_create_iiif_print_pending_relationships.rb +8 -6
  53. data/db/migrate/20231110163052_add_model_details_to_iiif_print_pending_relationships.rb +7 -0
  54. data/docker-compose.yml +2 -2
  55. data/iiif_print.gemspec +11 -10
  56. data/lib/generators/iiif_print/install_generator.rb +21 -1
  57. data/lib/generators/iiif_print/templates/config/initializers/iiif_print.rb +11 -4
  58. data/lib/generators/iiif_print/templates/helpers/iiif_print_helper.rb +5 -0
  59. data/lib/iiif_print/base_derivative_service.rb +14 -2
  60. data/lib/iiif_print/blacklight_iiif_search/annotation_decorator.rb +58 -6
  61. data/lib/iiif_print/catalog_search_builder.rb +7 -3
  62. data/lib/iiif_print/configuration.rb +205 -8
  63. data/lib/iiif_print/data/fileset_helper.rb +3 -3
  64. data/lib/iiif_print/data/work_derivatives.rb +4 -4
  65. data/lib/iiif_print/engine.rb +53 -15
  66. data/lib/iiif_print/errors.rb +18 -0
  67. data/lib/iiif_print/homepage_search_builder.rb +17 -0
  68. data/lib/iiif_print/image_tool.rb +12 -8
  69. data/lib/iiif_print/jp2_derivative_service.rb +4 -1
  70. data/lib/iiif_print/lineage_service.rb +47 -13
  71. data/lib/iiif_print/metadata.rb +67 -48
  72. data/lib/iiif_print/pdf_derivative_service.rb +3 -1
  73. data/lib/iiif_print/persistence_layer/active_fedora_adapter.rb +189 -0
  74. data/lib/iiif_print/persistence_layer/valkyrie_adapter.rb +183 -0
  75. data/lib/iiif_print/persistence_layer.rb +118 -0
  76. data/lib/iiif_print/split_pdfs/base_splitter.rb +153 -0
  77. data/lib/iiif_print/split_pdfs/child_work_creation_from_pdf_service.rb +83 -37
  78. data/lib/iiif_print/split_pdfs/derivative_rodeo_splitter.rb +166 -0
  79. data/lib/iiif_print/split_pdfs/destroy_pdf_child_works_service.rb +22 -0
  80. data/lib/iiif_print/split_pdfs/pages_to_jpgs_splitter.rb +19 -0
  81. data/lib/iiif_print/split_pdfs/pages_to_pngs_splitter.rb +26 -0
  82. data/lib/iiif_print/split_pdfs/pages_to_tiffs_splitter.rb +41 -0
  83. data/lib/iiif_print/split_pdfs/pdf_image_extraction_service.rb +64 -59
  84. data/lib/iiif_print/text_extraction/hocr_reader.rb +7 -3
  85. data/lib/iiif_print/text_extraction/page_ocr.rb +5 -4
  86. data/lib/iiif_print/text_extraction_derivative_service.rb +4 -2
  87. data/lib/iiif_print/text_formats_from_alto_service.rb +3 -1
  88. data/lib/iiif_print/tiff_derivative_service.rb +3 -1
  89. data/lib/iiif_print/version.rb +1 -1
  90. data/lib/iiif_print.rb +210 -20
  91. data/lib/samvera/derivatives/configuration.rb +83 -0
  92. data/lib/samvera/derivatives/hyrax.rb +129 -0
  93. data/lib/samvera/derivatives.rb +238 -0
  94. data/tasks/copy_authorities_to_test_app.rake +11 -0
  95. data/tasks/iiif_print_dev.rake +4 -4
  96. metadata +111 -196
  97. data/app/helpers/hyrax/iiif_helper.rb +0 -22
  98. data/app/indexers/concerns/iiif_print/child_indexer.rb +0 -34
  99. data/app/views/hyrax/file_sets/_actions.html.erb +0 -45
  100. data/bin/rails +0 -13
  101. data/lib/iiif_print/jobs/child_works_from_pdf_job.rb +0 -107
  102. data/lib/iiif_print/jobs/create_relationships_job.rb +0 -78
  103. data/lib/iiif_print/split_pdfs/pages_into_images_service.rb +0 -130
  104. data/spec/.keep.txt +0 -1
  105. data/spec/factories/ability.rb +0 -6
  106. data/spec/factories/newspaper_issue.rb +0 -7
  107. data/spec/factories/newspaper_page.rb +0 -7
  108. data/spec/factories/newspaper_page_solr_document.rb +0 -12
  109. data/spec/factories/newspaper_title.rb +0 -8
  110. data/spec/factories/uploaded_pdf_file.rb +0 -9
  111. data/spec/factories/uploaded_txt_file.rb +0 -9
  112. data/spec/factories/user.rb +0 -13
  113. data/spec/fixtures/files/4.1.07.jp2 +0 -0
  114. data/spec/fixtures/files/4.1.07.tiff +0 -0
  115. data/spec/fixtures/files/README.md +0 -7
  116. data/spec/fixtures/files/alto-2-0.xsd +0 -714
  117. data/spec/fixtures/files/broken-truncated.pdf +0 -0
  118. data/spec/fixtures/files/credits.md +0 -16
  119. data/spec/fixtures/files/lowres-gray-via-ndnp-sample.tiff +0 -0
  120. data/spec/fixtures/files/minimal-1-page.pdf +0 -0
  121. data/spec/fixtures/files/minimal-2-page.pdf +0 -0
  122. data/spec/fixtures/files/minimal-alto.xml +0 -31
  123. data/spec/fixtures/files/ndnp-alto-sample.xml +0 -24
  124. data/spec/fixtures/files/ndnp-sample1-json.json +0 -1
  125. data/spec/fixtures/files/ndnp-sample1-txt.txt +0 -1
  126. data/spec/fixtures/files/ndnp-sample1.pdf +0 -0
  127. data/spec/fixtures/files/ocr_alto.xml +0 -202
  128. data/spec/fixtures/files/ocr_alto_scaled_4pts_per_px.xml +0 -202
  129. data/spec/fixtures/files/ocr_color.tiff +0 -0
  130. data/spec/fixtures/files/ocr_gray.jp2 +0 -0
  131. data/spec/fixtures/files/ocr_gray.tiff +0 -0
  132. data/spec/fixtures/files/ocr_mono.tiff +0 -0
  133. data/spec/fixtures/files/ocr_mono_text_hocr.html +0 -78
  134. data/spec/fixtures/files/page1.tiff +0 -0
  135. data/spec/fixtures/files/sample-4page-issue.pdf +0 -0
  136. data/spec/fixtures/files/sample-color-newsletter.pdf +0 -0
  137. data/spec/fixtures/files/thumbnail.jpg +0 -0
  138. data/spec/helpers/hyrax/iiif_helper_spec.rb +0 -65
  139. data/spec/helpers/iiif_print_helper_spec.rb +0 -43
  140. data/spec/iiif_print/base_derivative_service_spec.rb +0 -11
  141. data/spec/iiif_print/blacklight_iiif_search/annotation_decorator_spec.rb +0 -51
  142. data/spec/iiif_print/catalog_search_builder_spec.rb +0 -60
  143. data/spec/iiif_print/configuration_spec.rb +0 -67
  144. data/spec/iiif_print/data/work_derivatives_spec.rb +0 -245
  145. data/spec/iiif_print/data/work_file_spec.rb +0 -99
  146. data/spec/iiif_print/data/work_files_spec.rb +0 -237
  147. data/spec/iiif_print/image_tool_spec.rb +0 -109
  148. data/spec/iiif_print/jobs/child_works_from_pdf_job_spec.rb +0 -30
  149. data/spec/iiif_print/jobs/create_relationships_job_spec.rb +0 -17
  150. data/spec/iiif_print/jp2_image_metadata_spec.rb +0 -37
  151. data/spec/iiif_print/lineage_service_spec.rb +0 -13
  152. data/spec/iiif_print/metadata_spec.rb +0 -115
  153. data/spec/iiif_print/split_pdfs/pages_into_images_service_spec.rb +0 -6
  154. data/spec/iiif_print/text_extraction/alto_reader_spec.rb +0 -49
  155. data/spec/iiif_print/text_extraction/hocr_reader_spec.rb +0 -45
  156. data/spec/iiif_print/text_extraction/page_ocr_spec.rb +0 -84
  157. data/spec/iiif_print/text_extraction/render_alto_spec.rb +0 -54
  158. data/spec/iiif_print/text_extraction/word_coords_builder_spec.rb +0 -44
  159. data/spec/iiif_print_spec.rb +0 -51
  160. data/spec/misc_shared.rb +0 -111
  161. data/spec/models/iiif_print/derivative_attachment_spec.rb +0 -37
  162. data/spec/models/iiif_print/ingest_file_relation_spec.rb +0 -56
  163. data/spec/models/solr_document_spec.rb +0 -14
  164. data/spec/presenters/iiif_print/iiif_manifest_presenter_behavior_spec.rb +0 -19
  165. data/spec/presenters/iiif_print/iiif_manifest_presenter_factory_behavior_spec.rb +0 -49
  166. data/spec/services/iiif_print/jp2_derivative_service_spec.rb +0 -59
  167. data/spec/services/iiif_print/pdf_derivative_service_spec.rb +0 -66
  168. data/spec/services/iiif_print/pluggable_derivative_service_spec.rb +0 -178
  169. data/spec/services/iiif_print/text_extraction_derivative_service_spec.rb +0 -82
  170. data/spec/services/iiif_print/text_formats_from_alto_service_spec.rb +0 -127
  171. data/spec/services/iiif_print/tiff_derivative_service_spec.rb +0 -65
  172. data/spec/spec_helper.rb +0 -181
  173. data/spec/support/controller_level_helpers.rb +0 -28
  174. data/spec/support/iiif_print_models.rb +0 -127
  175. data/spec/test_app_templates/blacklight.yml +0 -9
  176. data/spec/test_app_templates/fedora.yml +0 -15
  177. data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -40
  178. data/spec/test_app_templates/redis.yml +0 -9
  179. data/spec/test_app_templates/solr/conf/schema.xml +0 -362
  180. data/spec/test_app_templates/solr/conf/solrconfig.xml +0 -322
  181. data/spec/test_app_templates/solr.yml +0 -7
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Samvera
4
+ module Derivatives
5
+ # The default behavior of {Hyrax::FileSetDerivativesService} is to create a derivative and then
6
+ # apply it to the FileSet. This module wraps that behavior such that we can leverage the
7
+ # {Samvera::Derivatives} module and interfaces to handle cases where some of the derivatives
8
+ # already exist.
9
+ module Hyrax
10
+ # @note This conforms to the {Hyrax::DerivativeService} interface. The intention of this
11
+ # class is to be the sole registered {Hyrax::DerivativeService.services}
12
+ class ServiceShim
13
+ # @param file_set [FileSet]
14
+ # @param candidate_derivative_types [Array<Symbol>] the possible types of derivatives that
15
+ # we could create for this file_set.
16
+ # @param config [#registry_for]
17
+ #
18
+ # @todo We will want some kind of lambda to determine the candidate_derivative_types for this
19
+ # file_set.
20
+ def initialize(file_set, candidate_derivative_types: [], config: Samvera::Derivatives.config)
21
+ @file_set = file_set
22
+ @config = config
23
+ @derivatives = candidate_derivative_types.map { |type| config.registry_for(type: type) }
24
+ end
25
+
26
+ attr_reader :file_set
27
+
28
+ # @return [Array<Samvera::Derivatives::Configuration::RegisteredType>]
29
+ attr_reader :derivatives
30
+ attr_reader :config
31
+
32
+ def valid?
33
+ # We have a file set, which also means a parent work. I believe we always want this to be
34
+ # valid, because we want to leverage the locator/applicator behavior instead of the
35
+ # implicit work.
36
+ true
37
+ end
38
+
39
+ def cleanup_derivatives; end
40
+
41
+ # We have two vectors of consideration for derivative generation:
42
+ #
43
+ # - The desired derivatives for a file_set's parent work (e.g. the candidate derivatives)
44
+ # - The available derivatives for a file_set's mime type
45
+ def create_derivatives(file_path)
46
+ derivatives.each do |derivative|
47
+ Samvera::Derivatives.locate_and_apply_derivative_for(
48
+ file_set: file_set,
49
+ file_path: file_path,
50
+ derivative: derivative
51
+ )
52
+ end
53
+ end
54
+
55
+ def derivative_url(_destination_name)
56
+ ""
57
+ end
58
+ end
59
+
60
+ class FileApplicatorStrategy < Samvera::Derivatives::FileApplicator::Strategy
61
+ # With this set to true, we're telling the applicator to use the from_location
62
+ # (e.g. {Samvera::Derivatives::Hyrax::FileSetDerivativesServiceWrapper}) to apply the
63
+ # derivatives.
64
+ self.delegate_apply_to_given_from_location = true
65
+ end
66
+
67
+ class FileLocatorStrategy < Samvera::Derivatives::FileLocator::Strategy
68
+ # Implements {Samvera::Derivatives::FileLocator::Strategy} interface.
69
+ #
70
+ # @see Samvera::Derivatives::FileLocator::Strategy
71
+ #
72
+ # @return [Samvera::Derivatives::Hyrax::FileSetDerivativesServiceWrapper]
73
+ def self.locate(file_set:, file_path:, **)
74
+ file_set.samvera_derivatives_default_from_location_wrapper(file_path: file_path)
75
+ end
76
+ end
77
+
78
+ class FileSetDerivativesServiceWrapper
79
+ class_attribute :wrapped_derivative_service_class, default: ::Hyrax::FileSetDerivativesService
80
+
81
+ # @param file_set [FileSet]
82
+ # @param file_path [String]
83
+ def initialize(file_set:, file_path:)
84
+ @file_set = file_set
85
+ @file_path = file_path
86
+ @wrapped_derivative_service = wrapped_derivative_service_class.new(file_set)
87
+ end
88
+ attr_reader :file_set, :wrapped_derivative_service, :file_path
89
+
90
+ # @see Samvera::Derivatives::FileLocator.call
91
+ def present?
92
+ true
93
+ end
94
+
95
+ # @see Samvera::Derivatives::FileApplicator::Strategy
96
+ def apply!(*)
97
+ # Why the short-circuit? By the nature of the underlying
98
+ # ::Hyrax::FileSetDerivativesService, we generate multiple derivatives in one pass. But
99
+ # with the implementation of Samvera::Derivatives, we declare the derivatives and then
100
+ # iterate on locating and applying them. With this short-circuit, we will only apply the
101
+ # derivatives once.
102
+ return true if defined?(@already_applied)
103
+
104
+ return false unless wrapped_derivative_service.valid?
105
+
106
+ wrapped_derivative_service.create_derivatives(file_path)
107
+ @already_applied = true
108
+ end
109
+ end
110
+
111
+ ##
112
+ # The purpose of this module is to preserve the existing Hyrax derivative behavior while also
113
+ # allowing for the two-step tango of locator and applicator.
114
+ #
115
+ # @see Samvera::Derivatives.locate_and_apply_derivative_for
116
+ module FileSetDecorator
117
+ # @return [Samvera::Derivatives::Hyrax::FileSetDerivativesServiceWrapper]
118
+ def samvera_derivatives_default_from_location_wrapper(file_path:)
119
+ @samvera_derivatives_default_from_location_wrapper ||=
120
+ Samvera::Derivatives::Hyrax::FileSetDerivativesServiceWrapper.new(file_set: self, file_path: file_path)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ # TODO: We are likely going to want that.
128
+ # Hyrax::DerivativeService.services = [Samvera::Derivatives::Hyrax::ServiceShim]
129
+ FileSet.prepend(Samvera::Derivatives::Hyrax::FileSetDecorator)
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'samvera/derivatives/configuration'
4
+
5
+ ##
6
+ # Why Samvera and not Hyrax? Because there are folks creating non-Hyrax applications that will
7
+ # almost certainly want to leverage this work. And there might be switches for `defined?(Hyrax)`.
8
+ #
9
+ # Further the following four gems have interest in the interfaces of this module:
10
+ #
11
+ # - Hyrax
12
+ # - Hydra::Derivatives
13
+ # - Bulkrax
14
+ # - IiifPrint
15
+ #
16
+ # As such, it makes some sense to isolate the module and begin defining interfaces.
17
+ module Samvera
18
+ ##
19
+ # This module separates the finding/creation of a derivative binary (via {FileLocator}) and
20
+ # applying that derivative to the FileSet (via {FileApplicator}).
21
+ #
22
+ # In working on the interface and objects there is an effort to preserve backwards functionality
23
+ # while also allowing for a move away from that functionality.
24
+ #
25
+ # There are three primary concepts to consider:
26
+ #
27
+ # - Locator :: responsible for knowing where the derivative is
28
+ # - Location :: responsible for encapsulating the location
29
+ # - Applicator :: responsible for applying the located derivative to the FileSet
30
+ #
31
+ # The "trick" in this is in the polymorphism of the Location. Let's say we have the following
32
+ # desired functionality for the thumbnail derivative:
33
+ #
34
+ # ```gherkin
35
+ # Given a FileSet
36
+ # When I provide a thumbnail derivative
37
+ # Then I want to add that as the thumbnail for the FileSet
38
+ #
39
+ # Given a FileSet
40
+ # When I do not provide a thumbnail derivative
41
+ # Then I want to generate a thumbnail
42
+ # And add the generated as the thumbnail for the FileSet
43
+ # ```
44
+ #
45
+ # In the above case we would have two Locator strategies:
46
+ #
47
+ # - Find Existing One
48
+ # - Will Generate One (e.g. Hyrax::FileSetDerivativesService with Hydra::Derivative behavior)
49
+ #
50
+ # And we would have two Applicator strategies:
51
+ #
52
+ # - Apply an Existing One
53
+ # - Generate One and Apply (e.g. Hyrax::FileSetDerivativesService with Hydra::Derivative behavior)
54
+ #
55
+ # The Location from the first successful Locator will dictate how the ApplicatorStrategies do
56
+ # their work.
57
+ module Derivatives
58
+ ##
59
+ # @api public
60
+ #
61
+ # Responsible for configuration of derivatives.
62
+ #
63
+ # @example
64
+ # Samvera::Derivative.config do |config|
65
+ # config.register(type: :thumbnail, applicators: [CustomApplicator], locators: [CustomLocator]) do |file_set|
66
+ # file_set.video? || file_set.audio? || file_set.image?
67
+ # end
68
+ # end
69
+ #
70
+ # @yield [Configuration]
71
+ #
72
+ # @return [Configuration]
73
+ def self.config
74
+ @config ||= Configuration.new
75
+ yield(@config) if block_given?
76
+ @config
77
+ end
78
+
79
+ ##
80
+ # @api public
81
+ #
82
+ # Locate the derivative for the given :file_set and apply it to that :file_set.
83
+ #
84
+ # @param file_set [FileSet]
85
+ # @param derivative [Samvera::Derivatives::Configuration::RegisteredType]
86
+ # @param file_path [String]
87
+ #
88
+ # @note As a concession to existing implementations of creating derivatives, file_path is
89
+ # included as a parameter.
90
+ def self.locate_and_apply_derivative_for(file_set:, derivative:, file_path:)
91
+ return false unless derivative.applicable_for?(file_set: file_set)
92
+
93
+ from_location = FileLocator.call(
94
+ file_set: file_set,
95
+ file_path: file_path,
96
+ derivative: derivative
97
+ )
98
+
99
+ FileApplicator.call(
100
+ from_location: from_location,
101
+ file_set: file_set,
102
+ derivative: derivative
103
+ )
104
+ end
105
+
106
+ ##
107
+ # The purpose of this module is to find the derivative file path for a FileSet and a given
108
+ # derivative type (e.g. :thumbnail).
109
+ #
110
+ # @see https://github.com/samvera-labs/bulkrax/issues/760 Design Document
111
+ #
112
+ # @note Ideally, this module would be part of Hyrax or Hydra::Derivatives
113
+ # @see https://github.com/samvera/hyrax
114
+ # @see https://github.com/samvera/hydra-derivatives
115
+ module FileLocator
116
+ ##
117
+ # @api public
118
+ #
119
+ # This method is responsible for finding the correct file names for the given file set and
120
+ # derivative type.
121
+ #
122
+ # @param file_set [FileSet]
123
+ # @param file_path [String]
124
+ # @param derivative [Samvera::Derivatives::Configuration::RegisteredType]
125
+ #
126
+ # @return [Samvera::Derivatives::FromLocation]
127
+ #
128
+ # @note Why {.call}? This allows for a simple lambda interface, which can greatly ease testing
129
+ # and composition.
130
+ def self.call(file_set:, file_path:, derivative:)
131
+ from_location = nil
132
+
133
+ derivative.locators.each do |locator|
134
+ from_location = locator.locate(
135
+ file_set: file_set,
136
+ file_path: file_path,
137
+ derivative_type: derivative.type
138
+ )
139
+ break if from_location.present?
140
+ end
141
+
142
+ from_location
143
+ end
144
+
145
+ ##
146
+ # @abstract
147
+ #
148
+ # The purpose of this abstract class is to provide the public interface for strategies.
149
+ #
150
+ # @see {.find}
151
+ class Strategy
152
+ ##
153
+ # @api public
154
+ # @param file_set [FileSet]
155
+ # @param file_path [String]
156
+ # @param derivative_type [#to_sym]
157
+ #
158
+ # @return [Samvera::Derivatives::FromLocation] when this is a valid strategy
159
+ # @return [NilClass] when this is not a valid strategy
160
+ def self.locate(file_set:, file_path:, derivative_type:)
161
+ raise NotImplementedError
162
+ end
163
+ end
164
+ end
165
+
166
+ module FileApplicator
167
+ ##
168
+ # @api public
169
+ #
170
+ # @param file_set [FileSet]
171
+ # @param from_location [#present?]
172
+ # @param derivative [Array<#apply!>]
173
+ def self.call(file_set:, from_location:, derivative:)
174
+ # rubocop:disable Rails/Blank
175
+ return false unless from_location.present?
176
+ # rubocop:enable Rails/Blank
177
+
178
+ derivative.applicators.each do |applicator|
179
+ applicator.apply!(file_set: file_set, derivative_type: derivative.type, from_location: from_location)
180
+ end
181
+ end
182
+
183
+ ##
184
+ # @abstract
185
+ #
186
+ # The purpose of this abstract class is to provide the public interface for strategies.
187
+ #
188
+ # @see {.find}
189
+ class Strategy
190
+ # In some cases the FromLocation knows how to write itself; this is the case when we wrap
191
+ # the Hyrax::FileSetDerivativesService.
192
+ class_attribute :delegate_apply_to_given_from_location, default: false
193
+
194
+ ##
195
+ # @param file_set [FileSet]
196
+ # @param derivative_type [#to_sym]
197
+ # @param from_location [Object]
198
+ def self.apply!(file_set:, derivative_type:, from_location:)
199
+ new(file_set: file_set, derivative_type: derivative_type, from_location: from_location).apply!
200
+ end
201
+
202
+ def initialize(file_set:, derivative_type:, from_location:)
203
+ @file_set = file_set
204
+ @derivative_type = derivative_type
205
+ @from_location = from_location
206
+ end
207
+ attr_reader :file_set, :derivative_type, :from_location
208
+
209
+ # @note What's going on with this logic? To continue to leverage
210
+ # Hyrax::FileSetDerivativesService, we want to let that wrapped service (as a
211
+ # FromLocation) to do it's original work. However, we might have multiple strategies
212
+ # in play for application. That case is when we want to first check for an existing
213
+ # thumbnail and failing that generate the thumbnail. The from_location could either
214
+ # be the found thumbnail...or it could be the wrapped Hyrax::FileSetDerivativesService
215
+ # that will create the thumbnail and write it to the location. The two applicator
216
+ # strategies in that case would be the wrapper and logic that will write the found
217
+ # file to the correct derivative path.
218
+ def apply!
219
+ if delegate_apply_to_given_from_location?
220
+ return false unless from_location.respond_to?(:apply!)
221
+
222
+ from_location.apply!(file_set: file_set, derivative_type: derivative_type)
223
+ else
224
+ return false if from_location.respond_to?(:apply!)
225
+
226
+ perform_apply!
227
+ end
228
+ end
229
+
230
+ private
231
+
232
+ def perform_apply!
233
+ raise NotImplementedError
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,11 @@
1
+ namespace :engine_cart do
2
+ desc "Copy custom rights_statement and license questioning authority YAML files into the test app"
3
+ task copy_authorities: :generate do
4
+ test_app_path = ENV['ENGINE_CART_DESTINATION'] || File.expand_path(".internal_test_app", File.dirname(__FILE__))
5
+ src_dir = File.expand_path("../spec/fixtures/authorities", __dir__)
6
+ dest_dir = File.join(test_app_path, "config/authorities")
7
+
8
+ FileUtils.mkdir_p(dest_dir)
9
+ FileUtils.cp_r("#{src_dir}/.", dest_dir)
10
+ end
11
+ end
@@ -20,14 +20,14 @@ task :spec_with_app_load do
20
20
  end
21
21
 
22
22
  if ENV.fetch('IN_DOCKER', false)
23
- desc 'Generate the engine_cart and spin up test servers and run specs'
24
- task ci: %w[rubocop engine_cart:generate] do
23
+ desc 'Generate the engine_cart, copy authorities and spin up test servers and run specs'
24
+ task ci: %w[rubocop engine_cart:generate engine_cart:copy_authorities] do
25
25
  puts 'running continuous integration'
26
26
  Rake::Task['spec'].invoke
27
27
  end
28
28
  else
29
- desc 'Generate the engine_cart and spin up test servers and run specs'
30
- task ci: %w[rubocop engine_cart:generate] do
29
+ desc 'Generate the engine_cart, copy authorities and spin up test servers and run specs'
30
+ task ci: %w[rubocop engine_cart:generate engine_cart:copy_authorities] do
31
31
  puts 'running continuous integration'
32
32
  Rake::Task['spec_with_app_load'].invoke
33
33
  end