hyrax 5.1.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (561) hide show
  1. checksums.yaml +4 -4
  2. data/.dassie/.env +5 -1
  3. data/.dassie/Gemfile +5 -3
  4. data/.dassie/app/assets/images/bulkrax/removed.png +0 -0
  5. data/.dassie/app/assets/javascripts/application.js +2 -0
  6. data/.dassie/app/assets/stylesheets/application.css +1 -0
  7. data/.dassie/app/controllers/catalog_controller.rb +1 -0
  8. data/.dassie/app/forms/admin_set_resource_form.rb +6 -0
  9. data/.dassie/app/forms/collection_resource_form.rb +5 -2
  10. data/.dassie/app/forms/generic_work_resource_form.rb +5 -2
  11. data/.dassie/app/forms/monograph_form.rb +5 -3
  12. data/.dassie/app/indexers/admin_set_resource_indexer.rb +5 -0
  13. data/.dassie/app/indexers/collection_resource_indexer.rb +3 -3
  14. data/.dassie/app/indexers/generic_work_resource_indexer.rb +6 -3
  15. data/.dassie/app/indexers/monograph_indexer.rb +6 -2
  16. data/.dassie/app/models/ability.rb +8 -0
  17. data/.dassie/app/models/collection_resource.rb +4 -2
  18. data/.dassie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  19. data/.dassie/app/models/generic_work_resource.rb +5 -2
  20. data/.dassie/app/models/monograph.rb +5 -2
  21. data/.dassie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  22. data/.dassie/bin/importer +142 -0
  23. data/.dassie/bin/web +4 -0
  24. data/.dassie/config/application.rb +1 -1
  25. data/.dassie/config/browse_everything_providers.yml +1 -1
  26. data/.dassie/config/bulkrax_api.yml +86 -0
  27. data/.dassie/config/initializers/bulkrax.rb +92 -0
  28. data/.dassie/config/initializers/clamav.rb +2 -0
  29. data/.dassie/config/initializers/devise.rb +1 -0
  30. data/.dassie/config/initializers/hyrax.rb +7 -1
  31. data/.dassie/config/initializers/riiif.rb +4 -80
  32. data/.dassie/config/initializers/wings.rb +1 -1
  33. data/.dassie/config/metadata_profiles/m3_profile.yaml +929 -0
  34. data/.dassie/config/puma.rb +4 -2
  35. data/.dassie/config/routes.rb +7 -0
  36. data/.dassie/config/sidekiq.yml +17 -0
  37. data/.dassie/config/uv/uv.html +63 -81
  38. data/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  39. data/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  40. data/.dassie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  41. data/.dassie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  42. data/.dassie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  43. data/.dassie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  44. data/.dassie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  45. data/.dassie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  46. data/.dassie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  47. data/.dassie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  48. data/.dassie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  49. data/.dassie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  50. data/.dassie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  51. data/.dassie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  52. data/.dassie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  53. data/.dassie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  54. data/.dassie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  55. data/.dassie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  56. data/.dassie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  57. data/.dassie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  58. data/.dassie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  59. data/.dassie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  60. data/.dassie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  61. data/.dassie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  62. data/.dassie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  63. data/.dassie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  64. data/.dassie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  65. data/.dassie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  66. data/.dassie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  67. data/.dassie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  68. data/.dassie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  69. data/.dassie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  70. data/.dassie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  71. data/.dassie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  72. data/.dassie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  73. data/.dassie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  74. data/.dassie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  75. data/.dassie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  76. data/.dassie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  77. data/.dassie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  78. data/.dassie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  79. data/.dassie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  80. data/.dassie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  81. data/.dassie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  82. data/.dassie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  83. data/.dassie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  84. data/.dassie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  85. data/.dassie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  86. data/.dassie/db/schema.rb +263 -109
  87. data/.dassie/package.json +1 -1
  88. data/.dassie/rspec_split_configuration.json +835 -0
  89. data/.dassie/solr/conf/solrconfig.xml +21 -5
  90. data/.github/{ISSUE_TEMPLATE.md → ISSUE_TEMPLATE/issue_template.md} +5 -0
  91. data/.github/workflows/lint-build-test.yml +6 -2
  92. data/.github/workflows/release-charts.yml +48 -0
  93. data/.gitignore +6 -0
  94. data/.koppie/.env +5 -1
  95. data/.koppie/Gemfile +3 -1
  96. data/.koppie/app/assets/images/bulkrax/removed.png +0 -0
  97. data/.koppie/app/assets/javascripts/application.js +2 -0
  98. data/.koppie/app/assets/stylesheets/application.css +1 -0
  99. data/.koppie/app/controllers/catalog_controller.rb +1 -1
  100. data/.koppie/app/forms/collection_resource_form.rb +5 -2
  101. data/.koppie/app/forms/file_set_form.rb +5 -0
  102. data/.koppie/app/forms/generic_work_form.rb +5 -3
  103. data/.koppie/app/forms/monograph_form.rb +5 -3
  104. data/.koppie/app/indexers/collection_resource_indexer.rb +5 -2
  105. data/.koppie/app/indexers/file_set_indexer.rb +7 -0
  106. data/.koppie/app/indexers/generic_work_indexer.rb +6 -3
  107. data/.koppie/app/indexers/monograph_indexer.rb +6 -2
  108. data/.koppie/app/models/ability.rb +8 -0
  109. data/.koppie/app/models/collection_resource.rb +4 -2
  110. data/.koppie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  111. data/.koppie/app/models/generic_work.rb +5 -2
  112. data/.koppie/app/models/monograph.rb +5 -2
  113. data/.koppie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  114. data/.koppie/bin/importer +142 -0
  115. data/.koppie/bin/web +4 -0
  116. data/.koppie/config/browse_everything_providers.yml +2 -0
  117. data/.koppie/config/bulkrax_api.yml +86 -0
  118. data/.koppie/config/initializers/bulkrax.rb +92 -0
  119. data/.koppie/config/initializers/clamav.rb +2 -0
  120. data/.koppie/config/initializers/devise.rb +1 -1
  121. data/.koppie/config/initializers/hyrax.rb +11 -3
  122. data/.koppie/config/initializers/riiif.rb +4 -82
  123. data/.koppie/config/metadata_profiles/m3_profile.yaml +930 -0
  124. data/.koppie/config/routes.rb +7 -0
  125. data/.koppie/config/sidekiq.yml +2 -0
  126. data/.koppie/config/uv/uv.html +63 -81
  127. data/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  128. data/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  129. data/.koppie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  130. data/.koppie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  131. data/.koppie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  132. data/.koppie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  133. data/.koppie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  134. data/.koppie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  135. data/.koppie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  136. data/.koppie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  137. data/.koppie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  138. data/.koppie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  139. data/.koppie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  140. data/.koppie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  141. data/.koppie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  142. data/.koppie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  143. data/.koppie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  144. data/.koppie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  145. data/.koppie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  146. data/.koppie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  147. data/.koppie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  148. data/.koppie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  149. data/.koppie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  150. data/.koppie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  151. data/.koppie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  152. data/.koppie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  153. data/.koppie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  154. data/.koppie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  155. data/.koppie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  156. data/.koppie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  157. data/.koppie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  158. data/.koppie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  159. data/.koppie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  160. data/.koppie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  161. data/.koppie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  162. data/.koppie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  163. data/.koppie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  164. data/.koppie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  165. data/.koppie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  166. data/.koppie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  167. data/.koppie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  168. data/.koppie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  169. data/.koppie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  170. data/.koppie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  171. data/.koppie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  172. data/.koppie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  173. data/.koppie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  174. data/.koppie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  175. data/.koppie/db/schema.rb +154 -1
  176. data/.koppie/package.json +1 -1
  177. data/.koppie/rspec_split_configuration.json +835 -0
  178. data/.koppie/solr/conf/solrconfig.xml +0 -5
  179. data/.koppie/yarn.lock +5587 -752
  180. data/.rubocop.yml +1 -0
  181. data/CONTAINERS.md +12 -10
  182. data/Dockerfile +9 -22
  183. data/Gemfile +1 -1
  184. data/Gemfile.allinson +2 -0
  185. data/README.md +1 -2
  186. data/app/actors/hyrax/actors/file_actor.rb +2 -0
  187. data/app/actors/hyrax/actors/file_set_actor.rb +1 -1
  188. data/app/assets/javascripts/hyrax/app.js.erb +143 -10
  189. data/app/assets/javascripts/hyrax/collection_select.js +68 -0
  190. data/app/assets/javascripts/hyrax/copy_permalink_button.js +28 -0
  191. data/app/assets/javascripts/hyrax/redirects.js +45 -0
  192. data/app/assets/javascripts/hyrax/relationships/control.es6 +21 -1
  193. data/app/assets/javascripts/hyrax/select_work_type.es6 +7 -2
  194. data/app/assets/javascripts/hyrax.js +3 -1
  195. data/app/assets/stylesheets/hyrax/_file-show.scss +1 -0
  196. data/app/assets/stylesheets/hyrax/_viewer.scss +8 -0
  197. data/app/assets/stylesheets/hyrax/dashboard.scss +22 -1
  198. data/app/assets/stylesheets/hyrax/sidebar.scss +98 -3
  199. data/app/authorities/qa/authorities/collections.rb +9 -9
  200. data/app/controllers/concerns/hyrax/analytics_error_handling.rb +97 -0
  201. data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +3 -1
  202. data/app/controllers/concerns/hyrax/ensure_migrated_behavior.rb +50 -0
  203. data/app/controllers/concerns/hyrax/flexible_catalog_behavior.rb +206 -0
  204. data/app/controllers/concerns/hyrax/flexible_schema_behavior.rb +17 -0
  205. data/app/controllers/concerns/hyrax/redirect_to_display_url.rb +54 -0
  206. data/app/controllers/concerns/hyrax/valkyrie_downloads_controller_behavior.rb +1 -0
  207. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +54 -11
  208. data/app/controllers/hyrax/admin/admin_sets_controller.rb +21 -13
  209. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -0
  210. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +5 -4
  211. data/app/controllers/hyrax/admin/metadata_profiles_controller.rb +66 -0
  212. data/app/controllers/hyrax/batch_uploads_controller.rb +2 -0
  213. data/app/controllers/hyrax/dashboard/collections_controller.rb +27 -6
  214. data/app/controllers/hyrax/dashboard/nest_collections_controller.rb +2 -1
  215. data/app/controllers/hyrax/dashboard_controller.rb +2 -1
  216. data/app/controllers/hyrax/file_sets_controller.rb +20 -2
  217. data/app/controllers/hyrax/homepage_controller.rb +7 -0
  218. data/app/controllers/hyrax/my/works_controller.rb +2 -21
  219. data/app/controllers/hyrax/permissions_controller.rb +4 -2
  220. data/app/controllers/hyrax/redirects_controller.rb +56 -0
  221. data/app/controllers/hyrax/single_use_links_viewer_controller.rb +2 -1
  222. data/app/controllers/hyrax/transcripts_controller.rb +31 -0
  223. data/app/controllers/hyrax/uploads_controller.rb +18 -9
  224. data/app/forms/concerns/hyrax/based_near_field_behavior.rb +77 -0
  225. data/app/forms/concerns/hyrax/flexible_form_behavior.rb +37 -0
  226. data/app/forms/concerns/hyrax/redirects_field_behavior.rb +95 -0
  227. data/app/forms/concerns/hyrax/transcripts_behavior.rb +40 -0
  228. data/app/forms/hyrax/forms/admin_set_form.rb +1 -1
  229. data/app/forms/hyrax/forms/administrative_set_form.rb +3 -0
  230. data/app/forms/hyrax/forms/batch_edit_form.rb +1 -3
  231. data/app/forms/hyrax/forms/batch_upload_form.rb +14 -0
  232. data/app/forms/hyrax/forms/file_set_edit_form.rb +1 -1
  233. data/app/forms/hyrax/forms/file_set_form.rb +6 -7
  234. data/app/forms/hyrax/forms/pcdm_collection_form.rb +17 -5
  235. data/app/forms/hyrax/forms/pcdm_object_form.rb +11 -3
  236. data/app/forms/hyrax/forms/resource_batch_edit_form.rb +8 -22
  237. data/app/forms/hyrax/forms/resource_form.rb +110 -10
  238. data/app/forms/hyrax/forms.rb +1 -0
  239. data/app/helpers/hyrax/attributes_helper.rb +109 -0
  240. data/app/helpers/hyrax/blacklight_override.rb +26 -0
  241. data/app/helpers/hyrax/collections_helper.rb +2 -0
  242. data/app/helpers/hyrax/file_set_form_helper.rb +24 -0
  243. data/app/helpers/hyrax/hyrax_helper_behavior.rb +53 -4
  244. data/app/helpers/hyrax/iiif_helper.rb +11 -1
  245. data/app/helpers/hyrax/permalink_helper.rb +37 -0
  246. data/app/helpers/hyrax/redirects_tab_helper.rb +29 -0
  247. data/app/helpers/hyrax/trophy_helper.rb +1 -1
  248. data/app/helpers/hyrax/work_form_helper.rb +9 -5
  249. data/app/helpers/hyrax/works_helper.rb +14 -0
  250. data/app/indexers/concerns/hyrax/workflow_indexer.rb +30 -0
  251. data/app/indexers/hyrax/file_set_indexer.rb +1 -0
  252. data/app/indexers/hyrax/indexers/administrative_set_indexer.rb +2 -1
  253. data/app/indexers/hyrax/indexers/file_set_indexer.rb +6 -2
  254. data/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb +11 -1
  255. data/app/indexers/hyrax/indexers/pcdm_object_indexer.rb +25 -4
  256. data/app/indexers/hyrax/indexers/redirects_indexer.rb +29 -0
  257. data/app/indexers/hyrax/indexers/resource_indexer.rb +4 -0
  258. data/app/indexers/hyrax/indexers.rb +2 -0
  259. data/app/inputs/controlled_vocabulary_input.rb +7 -1
  260. data/app/jobs/concerns/hyrax/queued_job_behavior.rb +22 -0
  261. data/app/jobs/content_deposit_error_event_job.rb +14 -0
  262. data/app/jobs/create_work_job.rb +2 -0
  263. data/app/jobs/hyrax/propagate_change_depositor_job.rb +1 -1
  264. data/app/jobs/hyrax/queued_delete_job.rb +11 -0
  265. data/app/jobs/hyrax/queued_indexing_job.rb +11 -0
  266. data/app/jobs/migrate_files_to_valkyrie_job.rb +39 -21
  267. data/app/jobs/migrate_sipity_entity_job.rb +21 -0
  268. data/app/models/batch_upload_item.rb +4 -0
  269. data/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb +10 -0
  270. data/app/models/concerns/hyrax/ability.rb +7 -3
  271. data/app/models/concerns/hyrax/collection_behavior.rb +4 -0
  272. data/app/models/concerns/hyrax/file_set/transcripts.rb +16 -0
  273. data/app/models/concerns/hyrax/file_set_behavior.rb +9 -0
  274. data/app/models/concerns/hyrax/flexibility.rb +107 -0
  275. data/app/models/concerns/hyrax/redirects_normalization.rb +38 -0
  276. data/app/models/concerns/hyrax/solr_document/characterization.rb +1 -1
  277. data/app/models/concerns/hyrax/solr_document/metadata.rb +9 -0
  278. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +4 -0
  279. data/app/models/concerns/hyrax/solr_document_behavior.rb +28 -3
  280. data/app/models/concerns/hyrax/suppressible.rb +1 -1
  281. data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +1 -1
  282. data/app/models/concerns/hyrax/with_embargoes_and_leases.rb +30 -0
  283. data/app/models/concerns/hyrax/work_behavior.rb +8 -0
  284. data/app/models/hyrax/administrative_set.rb +1 -1
  285. data/app/models/hyrax/change_set.rb +3 -1
  286. data/app/models/hyrax/embargo.rb +3 -1
  287. data/app/models/hyrax/file_metadata.rb +22 -7
  288. data/app/models/hyrax/file_set.rb +4 -2
  289. data/app/models/hyrax/flexible_schema.rb +219 -0
  290. data/app/models/hyrax/lease.rb +3 -1
  291. data/app/models/hyrax/pcdm_collection.rb +4 -1
  292. data/app/models/hyrax/redirect.rb +64 -0
  293. data/app/models/hyrax/redirect_path.rb +14 -0
  294. data/app/models/hyrax/resource.rb +22 -25
  295. data/app/models/hyrax/riiif/file.rb +43 -0
  296. data/app/models/hyrax/riiif/file_resolver.rb +65 -0
  297. data/app/models/hyrax/uploaded_file.rb +9 -0
  298. data/app/models/hyrax/virus_scanner.rb +16 -3
  299. data/app/models/hyrax/work.rb +4 -1
  300. data/app/models/job_io_wrapper.rb +12 -3
  301. data/app/models/user_mailbox.rb +3 -1
  302. data/app/presenters/hyrax/admin_set_presenter.rb +11 -0
  303. data/app/presenters/hyrax/annotates_content.rb +35 -0
  304. data/app/presenters/hyrax/collection_presenter.rb +5 -1
  305. data/app/presenters/hyrax/displays_content.rb +133 -0
  306. data/app/presenters/hyrax/displays_image.rb +11 -4
  307. data/app/presenters/hyrax/displays_transcripts.rb +59 -0
  308. data/app/presenters/hyrax/file_set_presenter.rb +8 -18
  309. data/app/presenters/hyrax/google_scholar_presenter.rb +39 -0
  310. data/app/presenters/hyrax/iiif_manifest_presenter.rb +22 -4
  311. data/app/presenters/hyrax/missing_method_behavior.rb +15 -0
  312. data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +2 -4
  313. data/app/presenters/hyrax/work_show_presenter.rb +56 -14
  314. data/app/renderers/hyrax/renderers/attribute_renderer.rb +6 -2
  315. data/app/renderers/hyrax/renderers/license_attribute_renderer.rb +10 -10
  316. data/app/renderers/hyrax/renderers/redirects_label_attribute_renderer.rb +25 -0
  317. data/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb +10 -11
  318. data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +1 -5
  319. data/app/search_builders/hyrax/filter_by_type.rb +1 -1
  320. data/app/services/hyrax/action/create_valkyrie_work.rb +3 -2
  321. data/app/services/hyrax/analytics/ga4/base.rb +1 -1
  322. data/app/services/hyrax/analytics/ga4.rb +5 -1
  323. data/app/services/hyrax/authority_rendering_helper.rb +28 -0
  324. data/app/services/hyrax/authority_service.rb +107 -0
  325. data/app/services/hyrax/callbacks.rb +2 -2
  326. data/app/services/hyrax/change_depositor_service.rb +1 -1
  327. data/app/services/hyrax/characterization/valkyrie_characterization_service.rb +21 -13
  328. data/app/services/hyrax/collections/nested_collection_query_service.rb +9 -3
  329. data/app/services/hyrax/collections_service.rb +17 -0
  330. data/app/services/hyrax/custom_queries/find_by_property_value.rb +89 -0
  331. data/app/services/hyrax/custom_queries/find_ids_by_model.rb +31 -6
  332. data/app/services/hyrax/edit_permissions_service.rb +11 -10
  333. data/app/services/hyrax/file_set_type_service.rb +12 -4
  334. data/app/services/hyrax/flexible_schema_validator_service.rb +153 -0
  335. data/app/services/hyrax/flexible_schema_validators/class_validator.rb +123 -0
  336. data/app/services/hyrax/flexible_schema_validators/core_metadata_validator.rb +211 -0
  337. data/app/services/hyrax/flexible_schema_validators/existing_records_validator.rb +83 -0
  338. data/app/services/hyrax/flexible_schema_validators/redirects_validator.rb +116 -0
  339. data/app/services/hyrax/flexible_schema_validators/schema_validator.rb +34 -0
  340. data/app/services/hyrax/flexible_schema_validators/sort_properties_validator.rb +54 -0
  341. data/app/services/hyrax/license_service.rb +1 -1
  342. data/app/services/hyrax/listeners/metadata_index_listener.rb +11 -0
  343. data/app/services/hyrax/m3_profile_editor.rb +32 -0
  344. data/app/services/hyrax/m3_schema_loader.rb +119 -0
  345. data/app/services/hyrax/manifest_builder_service.rb +18 -24
  346. data/app/services/hyrax/permalink_path.rb +25 -0
  347. data/app/services/hyrax/qa_select_service.rb +9 -5
  348. data/app/services/hyrax/redirect_path_normalizer.rb +58 -0
  349. data/app/services/hyrax/redirects_lookup.rb +59 -0
  350. data/app/services/hyrax/resource_permissions_visibility_propagator.rb +54 -0
  351. data/app/services/hyrax/resource_types_service.rb +3 -20
  352. data/app/services/hyrax/rights_statement_service.rb +1 -1
  353. data/app/services/hyrax/schema_loader.rb +205 -0
  354. data/app/services/hyrax/search_service.rb +1 -1
  355. data/app/services/hyrax/simple_schema_loader.rb +28 -127
  356. data/app/services/hyrax/solr_service.rb +39 -2
  357. data/app/services/hyrax/tolerant_select_service.rb +5 -3
  358. data/app/services/hyrax/valkyrie_upload.rb +2 -2
  359. data/app/services/hyrax/visibility_propagator.rb +4 -1
  360. data/app/services/hyrax/work_uploads_handler.rb +17 -9
  361. data/app/services/hyrax/workflow/workflow_factory.rb +5 -4
  362. data/app/services/migrate_resource_service.rb +8 -2
  363. data/app/uploaders/hyrax/uploaded_file_uploader.rb +2 -2
  364. data/app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb +1 -1
  365. data/app/utils/hyrax/required_data_seeder.rb +1 -0
  366. data/app/utils/hyrax/required_data_seeders/collection_type_seeder.rb +1 -1
  367. data/app/utils/hyrax/required_data_seeders/flexible_profile_seeder.rb +28 -0
  368. data/app/validators/hyrax/controlled_vocabulary_validator.rb +64 -0
  369. data/app/validators/hyrax/redirect_validator.rb +128 -0
  370. data/app/views/_user_util_links.html.erb +2 -1
  371. data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
  372. data/app/views/collections/edit_fields/_schema_version.html.erb +1 -0
  373. data/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb +24 -2
  374. data/app/views/hyrax/admin/admin_sets/_show_document_list_row.html.erb +1 -1
  375. data/app/views/hyrax/admin/admin_sets/show.html.erb +1 -1
  376. data/app/views/hyrax/admin/analytics/_analytics_error.html.erb +42 -0
  377. data/app/views/hyrax/admin/analytics/collection_reports/_top_collections.html.erb +3 -7
  378. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +11 -9
  379. data/app/views/hyrax/admin/analytics/work_reports/_top_file_set_downloads.html.erb +3 -6
  380. data/app/views/hyrax/admin/analytics/work_reports/_top_works.html.erb +2 -3
  381. data/app/views/hyrax/admin/analytics/work_reports/_work_files.html.erb +1 -6
  382. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +60 -57
  383. data/app/views/hyrax/admin/features/index.html.erb +1 -1
  384. data/app/views/hyrax/admin/metadata_profiles/_import_modal.html.erb +20 -0
  385. data/app/views/hyrax/admin/metadata_profiles/index.html.erb +54 -0
  386. data/app/views/hyrax/base/_attribute_rows.html.erb +4 -21
  387. data/app/views/hyrax/base/_citations.html.erb +1 -0
  388. data/app/views/hyrax/base/_currently_shared.html.erb +2 -1
  389. data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
  390. data/app/views/hyrax/base/_form_member_of_collections.html.erb +6 -6
  391. data/app/views/hyrax/base/_form_redirects.html.erb +125 -0
  392. data/app/views/hyrax/base/_form_share.html.erb +7 -2
  393. data/app/views/hyrax/base/_member.html.erb +1 -1
  394. data/app/views/hyrax/base/_social_media.html.erb +3 -1
  395. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
  396. data/app/views/hyrax/base/show.html.erb +3 -0
  397. data/app/views/hyrax/collections/_default_group.html.erb +3 -0
  398. data/app/views/hyrax/collections/_list_collections.html.erb +3 -0
  399. data/app/views/hyrax/collections/_list_works.html.erb +1 -1
  400. data/app/views/hyrax/collections/_show_document_list_row.html.erb +1 -1
  401. data/app/views/hyrax/collections/show.html.erb +4 -0
  402. data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -2
  403. data/app/views/hyrax/dashboard/collections/_button_for_update_collection.html.erb +2 -1
  404. data/app/views/hyrax/dashboard/collections/_default_group.html.erb +3 -0
  405. data/app/views/hyrax/dashboard/collections/_form.html.erb +17 -0
  406. data/app/views/hyrax/dashboard/collections/_form_for_select_collection.html.erb +7 -10
  407. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +3 -0
  408. data/app/views/hyrax/dashboard/collections/_list_works.html.erb +1 -1
  409. data/app/views/hyrax/dashboard/collections/_show_document_list_menu.html.erb +13 -12
  410. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  411. data/app/views/hyrax/dashboard/profiles/_edit_primary.html.erb +1 -8
  412. data/app/views/hyrax/dashboard/profiles/_trophy_edit.html.erb +1 -1
  413. data/app/views/hyrax/dashboard/profiles/show.html.erb +5 -5
  414. data/app/views/hyrax/dashboard/sidebar/_metadata.html.erb +11 -0
  415. data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +1 -0
  416. data/app/views/hyrax/dashboard/works/_default_group.html.erb +3 -0
  417. data/app/views/hyrax/dashboard/works/_list_works.html.erb +4 -2
  418. data/app/views/hyrax/file_sets/_form.html.erb +16 -3
  419. data/app/views/hyrax/file_sets/_metadata.html.erb +35 -0
  420. data/app/views/hyrax/file_sets/_valkyrie_form.html.erb +37 -0
  421. data/app/views/hyrax/file_sets/edit.html.erb +14 -8
  422. data/app/views/hyrax/file_sets/media_display/_audio.html.erb +4 -0
  423. data/app/views/hyrax/file_sets/media_display/_image.html.erb +2 -2
  424. data/app/views/hyrax/file_sets/media_display/_video.html.erb +4 -0
  425. data/app/views/hyrax/homepage/_explore_collections.html.erb +1 -1
  426. data/app/views/hyrax/homepage/_featured_fields.html.erb +1 -1
  427. data/app/views/hyrax/homepage/_recent_document.html.erb +1 -1
  428. data/app/views/hyrax/homepage/robots.text.erb +17 -0
  429. data/app/views/hyrax/my/_admin_set_action_menu.html.erb +31 -27
  430. data/app/views/hyrax/my/_collection_action_menu.html.erb +40 -35
  431. data/app/views/hyrax/my/_work_action_menu.html.erb +23 -22
  432. data/app/views/hyrax/my/collections/_default_group.html.erb +3 -0
  433. data/app/views/hyrax/my/collections/_list_collections.html.erb +3 -0
  434. data/app/views/hyrax/my/collections/_modal_add_subcollection.html.erb +2 -2
  435. data/app/views/hyrax/my/collections/_modal_add_to_collection.html.erb +2 -2
  436. data/app/views/hyrax/my/works/_default_group.html.erb +3 -0
  437. data/app/views/hyrax/my/works/_list_works.html.erb +5 -2
  438. data/app/views/hyrax/shared/_copy_permalink.html.erb +10 -0
  439. data/app/views/hyrax/users/_user_info.html.erb +1 -6
  440. data/app/views/layouts/_head_tag_content.html.erb +2 -0
  441. data/app/views/layouts/hyrax/dashboard.html.erb +2 -1
  442. data/app/views/records/edit_fields/_contexts.html.erb +1 -0
  443. data/app/views/records/edit_fields/_license.html.erb +17 -5
  444. data/app/views/records/edit_fields/_resource_type.html.erb +16 -2
  445. data/app/views/records/edit_fields/_rights_statement.html.erb +17 -5
  446. data/app/views/records/edit_fields/_schema_version.html.erb +1 -0
  447. data/app/views/records/edit_fields/_transcript_ids.html.erb +18 -0
  448. data/app/views/records/show_fields/_rights.html.erb +1 -1
  449. data/app/views/shared/_citations.html.erb +46 -31
  450. data/app/views/shared/_schema_version.html.erb +38 -0
  451. data/bin/dev-entrypoint.sh +14 -4
  452. data/chart/hyrax/Chart.yaml +4 -4
  453. data/chart/hyrax/templates/ingress.yaml +3 -0
  454. data/chart/hyrax/values.yaml +10 -8
  455. data/config/features.rb +77 -40
  456. data/config/initializers/blacklight_dynamic_sitemap.rb +43 -0
  457. data/config/initializers/deprecation_patch.rb +27 -0
  458. data/config/initializers/hydra_works.rb +3 -0
  459. data/config/initializers/i18n_extensions.rb +197 -0
  460. data/config/initializers/indexing_adapter_initializer.rb +4 -0
  461. data/config/initializers/new_framework_defaults_7_2.rb +6 -4
  462. data/config/initializers/reform_rails_6_1_monkey_patch.rb +29 -0
  463. data/config/initializers/storage_adapter_initializer.rb +15 -9
  464. data/config/locales/hyrax.de.yml +172 -54
  465. data/config/locales/hyrax.en.yml +183 -66
  466. data/config/locales/hyrax.es.yml +174 -49
  467. data/config/locales/hyrax.fr.yml +169 -45
  468. data/config/locales/hyrax.it.yml +172 -48
  469. data/config/locales/hyrax.pt-BR.yml +172 -54
  470. data/config/locales/hyrax.zh.yml +145 -21
  471. data/config/metadata/basic_metadata.yaml +66 -0
  472. data/config/metadata/batch_edit_metadata.yaml +119 -0
  473. data/config/metadata/core_metadata.yaml +1 -0
  474. data/config/metadata/file_set_metadata.yaml +19 -0
  475. data/config/metadata/redirects.yaml +15 -0
  476. data/config/metadata_profiles/m3_json_schema.json +487 -0
  477. data/config/metadata_profiles/m3_profile.yaml +954 -0
  478. data/config/routes.rb +9 -0
  479. data/docker-compose-allinson.yml +176 -0
  480. data/docker-compose-dassie.yml +18 -10
  481. data/docker-compose-koppie.yml +18 -10
  482. data/docker-compose-sirenia.yml +20 -10
  483. data/documentation/copy_permalink.md +29 -0
  484. data/documentation/developing-your-hyrax-based-app.md +2 -2
  485. data/documentation/file-ingest-characterization.md +763 -0
  486. data/documentation/flexible_metadata.md +113 -0
  487. data/documentation/forms/field_behaviors.md +297 -0
  488. data/documentation/redirects.md +428 -0
  489. data/hyrax.gemspec +9 -4
  490. data/lib/freyja/metadata_adapter.rb +1 -1
  491. data/lib/freyja/persister.rb +36 -5
  492. data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +2 -2
  493. data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +5 -1
  494. data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +5 -1
  495. data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +6 -1
  496. data/lib/generators/hyrax/iiif_viewer/USAGE +22 -0
  497. data/lib/generators/hyrax/iiif_viewer/iiif_viewer_generator.rb +49 -0
  498. data/lib/generators/hyrax/iiif_viewer/templates/_clover.html.erb +7 -0
  499. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.css +3328 -0
  500. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.html +16 -0
  501. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.js +237 -0
  502. data/lib/generators/hyrax/install_generator.rb +25 -1
  503. data/lib/generators/hyrax/riiif_generator.rb +1 -1
  504. data/lib/generators/hyrax/templates/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  505. data/lib/generators/hyrax/templates/config/clamav.rb +2 -0
  506. data/lib/generators/hyrax/templates/config/initializers/riiif.rb +4 -80
  507. data/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb +9 -0
  508. data/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb +5 -0
  509. data/lib/generators/hyrax/templates/db/migrate/20260430000001_create_hyrax_redirect_paths.rb.erb +22 -0
  510. data/lib/generators/hyrax/templates/db/migrate/20260521003627_add_additional_redirect_info.rb.erb +39 -0
  511. data/lib/generators/hyrax/templates/package.json +1 -1
  512. data/lib/generators/hyrax/templates/uv.html +60 -82
  513. data/lib/generators/hyrax/work/templates/indexer.rb.erb +1 -1
  514. data/lib/generators/hyrax/work/templates/model.rb.erb +5 -1
  515. data/lib/generators/hyrax/work_resource/templates/form.rb.erb +5 -2
  516. data/lib/generators/hyrax/work_resource/templates/indexer.rb.erb +6 -2
  517. data/lib/generators/hyrax/work_resource/templates/work.rb.erb +5 -2
  518. data/lib/generators/hyrax/work_resource/work_resource_generator.rb +1 -0
  519. data/lib/hyrax/active_fedora_dummy_model.rb +6 -0
  520. data/lib/hyrax/configuration.rb +219 -10
  521. data/lib/hyrax/controlled_vocabulary/importer/language.rb +5 -1
  522. data/lib/hyrax/deprecation.rb +31 -0
  523. data/lib/hyrax/engine.rb +2 -0
  524. data/lib/hyrax/form_fields.rb +17 -5
  525. data/lib/hyrax/indexer.rb +31 -2
  526. data/lib/hyrax/resource_sync/resource_list_writer.rb +3 -0
  527. data/lib/hyrax/schema.rb +15 -4
  528. data/lib/hyrax/specs/shared_specs/factories/administrative_sets.rb +12 -0
  529. data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +1 -1
  530. data/lib/hyrax/specs/shared_specs/factories/hyrax_file_set.rb +13 -0
  531. data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +5 -1
  532. data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +14 -0
  533. data/lib/hyrax/specs/shared_specs/simple_work.rb +41 -0
  534. data/lib/hyrax/specs/shared_specs.rb +1 -0
  535. data/lib/hyrax/transactions/collection_create.rb +2 -1
  536. data/lib/hyrax/transactions/collection_destroy.rb +1 -0
  537. data/lib/hyrax/transactions/collection_update.rb +2 -1
  538. data/lib/hyrax/transactions/container.rb +28 -0
  539. data/lib/hyrax/transactions/steps/add_file_sets.rb +2 -1
  540. data/lib/hyrax/transactions/steps/apply_permission_template_on_update.rb +65 -0
  541. data/lib/hyrax/transactions/steps/apply_workflow_on_admin_set_change.rb +97 -0
  542. data/lib/hyrax/transactions/steps/ensure_admin_set.rb +1 -1
  543. data/lib/hyrax/transactions/steps/remove_redirect_paths.rb +35 -0
  544. data/lib/hyrax/transactions/steps/save.rb +10 -0
  545. data/lib/hyrax/transactions/steps/set_default_admin_set.rb +1 -1
  546. data/lib/hyrax/transactions/steps/sync_redirect_paths.rb +141 -0
  547. data/lib/hyrax/transactions/work_create.rb +2 -1
  548. data/lib/hyrax/transactions/work_destroy.rb +1 -0
  549. data/lib/hyrax/transactions/work_update.rb +4 -1
  550. data/lib/hyrax/version.rb +1 -1
  551. data/lib/hyrax.rb +62 -0
  552. data/lib/tasks/m3_profile_cleanup.rake +35 -0
  553. data/lib/valkyrie/indexing/redis_queue/indexing_adapter.rb +144 -0
  554. data/lib/wings/valkyrie/query_service.rb +3 -4
  555. data/template.rb +4 -1
  556. metadata +327 -25
  557. data/.dassie/public/robots.txt +0 -1
  558. data/.github/workflows/main.yml +0 -17
  559. data/.koppie/public/robots.txt +0 -1
  560. data/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb +0 -39
  561. data/app/views/catalog/_thumbnail_list_collection.html.erb +0 -4
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ if defined?(Riiif::Image)
3
+ module Hyrax
4
+ module Riiif
5
+ # Adds file locking to Riiif::File
6
+ # @see Riiif::FileResolver
7
+ class FileResolver
8
+ include ActiveSupport::Benchmarkable
9
+
10
+ # @param [String] id from iiif manifest
11
+ # @return [Riiif::File]
12
+ def find(id)
13
+ path = nil
14
+ file_locks[id].with_write_lock do
15
+ path = build_path(id)
16
+ path = build_path(id, force: true) unless ::File.exist?(path) # Ensures the file is locally available
17
+ end
18
+ Hyrax::Riiif::File.new(path, id: id)
19
+ end
20
+
21
+ # tracks individual file locks
22
+ # @see Hyrax::Riiif::File
23
+ # @return [Concurrent::Map<Concurrent::ReadWriteLock>]
24
+ def file_locks
25
+ @file_locks ||= Concurrent::Map.new do |k, v|
26
+ k.compute_if_absent(v) { Concurrent::ReadWriteLock.new }
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def build_path(id, force: false)
33
+ ::Riiif::Image.cache.fetch("riiif:" + Digest::MD5.hexdigest("path:#{id}"),
34
+ expires_in: ::Riiif::Image.expires_in,
35
+ force: force) do
36
+ load_file(id)
37
+ end
38
+ end
39
+
40
+ def load_file(id)
41
+ benchmark "Hyrax::Riiif::FileResolver loaded #{id}", level: :debug do
42
+ fs_id = id.sub(/\A([^\/]*)\/.*/, '\1')
43
+ file_set = Hyrax.query_service.find_by(id: fs_id)
44
+ file_metadata = Hyrax.custom_queries.find_original_file(file_set: file_set)
45
+ file_metadata.file.disk_path.to_s # Stores a local copy in tmpdir
46
+ end
47
+ end
48
+
49
+ def logger
50
+ Hyrax.logger
51
+ end
52
+ end
53
+ end
54
+ end
55
+ else
56
+ module Hyrax
57
+ module Riiif
58
+ class FileResolver
59
+ def initialize(*)
60
+ raise 'Riiif not available'
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -14,6 +14,8 @@ module Hyrax
14
14
  dependent: :destroy
15
15
  belongs_to :user, class_name: '::User'
16
16
 
17
+ validate :virus_scan
18
+
17
19
  ##
18
20
  # Associate a {FileSet} with this uploaded file.
19
21
  #
@@ -28,5 +30,12 @@ module Hyrax
28
30
  end
29
31
  update!(file_set_uri: uri)
30
32
  end
33
+
34
+ private
35
+
36
+ def virus_scan
37
+ errors.add(:file, I18n.t('hyrax.virus_scanner.virus_detected', filename: file.path)) if
38
+ file.path && Hyrax::VirusScanner.infected?(file.path)
39
+ end
31
40
  end
32
41
  end
@@ -38,10 +38,25 @@ module Hyrax
38
38
  #
39
39
  # @return [Boolean]
40
40
  def infected?
41
- defined?(ClamAV) ? clam_av_scanner : null_scanner
41
+ if defined?(Clamby)
42
+ clamby_scanner
43
+ elsif defined?(ClamAV)
44
+ clam_av_scanner
45
+ else
46
+ null_scanner
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def clamby_scanner
53
+ scan_result = Clamby.virus?(file)
54
+ warning("A virus was found in #{file}") if scan_result
55
+ scan_result
42
56
  end
43
57
 
44
58
  def clam_av_scanner
59
+ Deprecation.warn("ClamAV support has been deprecated. Please use Clamby instead.")
45
60
  scan_result = ClamAV.instance.method(:scanfile).call(file)
46
61
  return false if scan_result.zero?
47
62
  warning "A virus was found in #{file}: #{scan_result}"
@@ -58,8 +73,6 @@ module Hyrax
58
73
  false
59
74
  end
60
75
 
61
- private
62
-
63
76
  def warning(msg)
64
77
  Hyrax.logger&.warn(msg)
65
78
  end
@@ -94,7 +94,10 @@ module Hyrax
94
94
  # @see https://wiki.lyrasis.org/display/samvera/Hydra::Works+Shared+Modeling
95
95
  # for a historical perspective.
96
96
  class Work < Hyrax::Resource
97
- include Hyrax::Schema(:core_metadata)
97
+ include Hyrax::Schema(:core_metadata) if Hyrax.config.work_default_metadata
98
+ # See documentation/redirects.md for the redirects feature.
99
+ include Hyrax::Schema(:redirects) if Hyrax.config.work_default_metadata && Hyrax.config.redirects_enabled?
100
+ include Hyrax::RedirectsNormalization if Hyrax.config.redirects_enabled?
98
101
 
99
102
  attribute :admin_set_id, Valkyrie::Types::ID
100
103
  attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true)
@@ -25,6 +25,8 @@ class JobIoWrapper < ApplicationRecord
25
25
  after_initialize :static_defaults
26
26
  delegate :read, to: :file
27
27
 
28
+ attr_accessor :use_valkyrie
29
+
28
30
  # Responsible for creating a JobIoWrapper from the given parameters, with a
29
31
  # focus on sniffing out attributes from the given :file.
30
32
  #
@@ -34,8 +36,8 @@ class JobIoWrapper < ApplicationRecord
34
36
  # @param [FileSet] file_set - The associated file set
35
37
  # @return [JobIoWrapper]
36
38
  # @raise ActiveRecord::RecordInvalid - if the instance is not valid
37
- def self.create_with_varied_file_handling!(user:, file:, relation:, file_set:)
38
- args = { user: user, relation: relation.to_s, file_set_id: file_set.id }
39
+ def self.create_with_varied_file_handling!(user:, file:, relation:, file_set:, use_valkyrie: nil)
40
+ args = { user: user, relation: relation.to_s, file_set_id: file_set.id, use_valkyrie: use_valkyrie }
39
41
  if file.is_a?(Hyrax::UploadedFile)
40
42
  args[:uploaded_file] = file
41
43
  args[:path] = file.uploader.path
@@ -49,6 +51,12 @@ class JobIoWrapper < ApplicationRecord
49
51
  create!(args)
50
52
  end
51
53
 
54
+ def initialize(attributes = {})
55
+ @use_valkyrie = attributes&.delete(:use_valkyrie)
56
+ @use_valkyrie = Hyrax.config.use_valkyrie? if @use_valkyrie.nil?
57
+ super(attributes)
58
+ end
59
+
52
60
  def original_name
53
61
  super || extracted_original_name
54
62
  end
@@ -63,7 +71,8 @@ class JobIoWrapper < ApplicationRecord
63
71
  nil # unable to determine
64
72
  end
65
73
 
66
- def file_set(use_valkyrie: Hyrax.config.query_index_from_valkyrie)
74
+ def file_set(use_valkyrie: nil)
75
+ use_valkyrie ||= @use_valkyrie
67
76
  return FileSet.find(file_set_id) unless use_valkyrie
68
77
  Hyrax.query_service.find_by(id: Valkyrie::ID.new(file_set_id))
69
78
  end
@@ -49,7 +49,9 @@ class UserMailbox
49
49
  end
50
50
 
51
51
  def preferred_locale
52
- user.preferred_locale || I18n.default_locale
52
+ return I18n.default_locale unless I18n.locale_available?(user.preferred_locale)
53
+
54
+ user.preferred_locale
53
55
  end
54
56
 
55
57
  def empty_trash(user)
@@ -1,6 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
3
  class AdminSetPresenter < CollectionPresenter
4
+ delegate :contexts, to: :solr_document
5
+
6
+ def self.terms
7
+ base = super
8
+ if Hyrax.config.flexible? && Hyrax.config.admin_set_class.new.respond_to?(:contexts)
9
+ base | [:contexts]
10
+ else
11
+ base
12
+ end
13
+ end
14
+
4
15
  ##
5
16
  # @return [Boolean] true if there are items
6
17
  def any_items?
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ module AnnotatesContent
5
+ extend ActiveSupport::Concern
6
+
7
+ include DisplaysTranscripts
8
+
9
+ def annotation_content
10
+ transcription_content if video? || audio?
11
+ end
12
+
13
+ private
14
+
15
+ def transcription_content
16
+ transcripts.map do |doc|
17
+ options = {
18
+ type: 'Text',
19
+ motivation: 'supplementing',
20
+ body_id: transcript_url(doc, host: hostname, file_ext: file_ext(doc.mime_type)),
21
+ format: doc.mime_type,
22
+ label: doc.title_or_label
23
+ }
24
+ options[:language] = language_code(doc.language) if language_code(doc.language)
25
+ IIIFManifest::V3::AnnotationContent.new(**options)
26
+ end
27
+ end
28
+
29
+ # If you change the accepted mime types in Hyrax::TranscriptsBehavior,
30
+ # you may also want to override this method
31
+ def file_ext(_mime_type)
32
+ "vtt"
33
+ end
34
+ end
35
+ end
@@ -25,7 +25,7 @@ module Hyrax
25
25
 
26
26
  # CurationConcern methods
27
27
  delegate :stringify_keys, :human_readable_type, :collection?, :representative_id,
28
- :to_s, to: :solr_document
28
+ :to_s, :schema_version, to: :solr_document
29
29
 
30
30
  delegate(*Hyrax::CollectionType.settings_attributes, to: :collection_type, prefix: :collection_type_is)
31
31
  alias nestable? collection_type_is_nestable?
@@ -129,6 +129,10 @@ module Hyrax
129
129
  current_ability.can?(:deposit, solr_document)
130
130
  end
131
131
 
132
+ def editor?
133
+ current_ability.can?(:edit, self)
134
+ end
135
+
132
136
  def user_can_create_new_nest_collection?
133
137
  current_ability.can?(:create_collection_of_type, collection_type)
134
138
  end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ # rubocop:disable Metrics/ModuleLength
5
+ module DisplaysContent
6
+ extend ActiveSupport::Concern
7
+ # Creates a display content only where FileSet is an image, audio, or video.
8
+ #
9
+ # @return [IIIFManifest::V3::DisplayContent] the display content required by the manifest builder.
10
+ def display_content
11
+ return nil unless ability.can?(:read, object)
12
+
13
+ return image_content if image?
14
+ return video_content if video? && Flipflop.iiif_av?
15
+ return audio_content if audio? && Flipflop.iiif_av?
16
+ return pdf_content if pdf? && Flipflop.iiif_pdf?
17
+ end
18
+
19
+ private
20
+
21
+ def content_supported?
22
+ video? || audio? || image? || pdf?
23
+ end
24
+
25
+ def image_content
26
+ return nil unless latest_file_id
27
+ # Only provide v3 content when using v3 factory
28
+ # Otherwise let display_image handle v2
29
+ return nil unless Hyrax.config.iiif_manifest_factory == ::IIIFManifest::V3::ManifestFactory
30
+
31
+ url = Hyrax.config.iiif_image_url_builder.call(
32
+ latest_file_id,
33
+ hostname,
34
+ Hyrax.config.iiif_image_size_default,
35
+ image_format(alpha_channels)
36
+ )
37
+
38
+ image_content_v3(url)
39
+ end
40
+
41
+ def image_content_v3(url)
42
+ # @see https://github.com/samvera-labs/iiif_manifest
43
+ IIIFManifest::V3::DisplayContent.new(
44
+ url,
45
+ format: image_format(alpha_channels),
46
+ width: width,
47
+ height: height,
48
+ type: 'Image',
49
+ iiif_endpoint: iiif_endpoint(latest_file_id)
50
+ )
51
+ end
52
+
53
+ def video_content
54
+ # @see https://github.com/samvera-labs/iiif_manifest
55
+ IIIFManifest::V3::DisplayContent.new(
56
+ download_path('mp4'),
57
+ label: 'mp4',
58
+ width: Array(width).first.try(:to_i),
59
+ height: Array(height).first.try(:to_i),
60
+ duration: conformed_duration,
61
+ type: 'Video',
62
+ format: mime_type,
63
+ thumbnail: thumbnail
64
+ )
65
+ end
66
+
67
+ def audio_content
68
+ IIIFManifest::V3::DisplayContent.new(
69
+ download_path('mp3'),
70
+ label: 'mp3',
71
+ duration: conformed_duration,
72
+ type: 'Sound',
73
+ # I think UV has a bug where if it's 'audio/mpeg' then it would load, so adding this
74
+ # workaround to use 'audio/mp3' (which isn't even an official MIME type).
75
+ format: Hyrax.config.iiif_av_viewer == :universal_viewer ? 'audio/mp3' : mime_type,
76
+ thumbnail: [{
77
+ id: "#{hostname}/assets/audio.png",
78
+ type: 'Image',
79
+ format: 'image/png'
80
+ }]
81
+ )
82
+ end
83
+
84
+ def pdf_content
85
+ IIIFManifest::V3::DisplayContent.new(
86
+ download_path('pdf'),
87
+ label: 'pdf',
88
+ type: 'Text',
89
+ format: mime_type,
90
+ thumbnail: thumbnail
91
+ )
92
+ end
93
+
94
+ def download_path(extension)
95
+ Hyrax::Engine.routes.url_helpers.download_url(object, file: extension, host: hostname)
96
+ end
97
+
98
+ def thumbnail
99
+ [{
100
+ id: download_path('thumbnail'),
101
+ type: 'Image',
102
+ format: 'image/jpeg'
103
+ }]
104
+ end
105
+
106
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
107
+ def conformed_duration
108
+ duration_string = Array(object.duration).first
109
+ return nil if duration_string.blank?
110
+
111
+ # Handle values with explicit seconds unit (e.g., "25 s")
112
+ return duration_string.to_f if duration_string.match?(/\A[\d.]+\s*s\z/)
113
+ # Handle plain millisecond values (e.g., "120000")
114
+ return duration_string.to_f / 1000.0 unless duration_string.include?(':')
115
+
116
+ # Parse time-formatted strings
117
+ parts = duration_string.split(':').map(&:to_i)
118
+
119
+ case parts.length
120
+ when 2 # MM:SS
121
+ parts[0] * 60.0 + parts[1]
122
+ when 3 # H:MM:SS
123
+ parts[0] * 3600.0 + parts[1] * 60.0 + parts[2]
124
+ when 4 # H:MM:SS:mmm (milliseconds)
125
+ parts[0] * 3600.0 + parts[1] * 60.0 + parts[2] + (parts[3] / 1000.0)
126
+ else
127
+ duration_string.to_f # fallback
128
+ end
129
+ end
130
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
131
+ end
132
+ # rubocop:enable Metrics/ModuleLength
133
+ end
@@ -15,7 +15,7 @@ module Hyrax
15
15
  return nil unless latest_file_id
16
16
 
17
17
  # @see https://github.com/samvera-labs/iiif_manifest
18
- IIIFManifest::DisplayImage.new(display_image_url(request.base_url),
18
+ IIIFManifest::DisplayImage.new(display_image_url,
19
19
  format: image_format(alpha_channels),
20
20
  width: width,
21
21
  height: height,
@@ -24,7 +24,12 @@ module Hyrax
24
24
 
25
25
  private
26
26
 
27
- def display_image_url(base_url)
27
+ def base_url_for_iiif
28
+ respond_to?(:request) && request ? request.base_url : hostname
29
+ end
30
+
31
+ def display_image_url(base_url = nil)
32
+ base_url ||= base_url_for_iiif
28
33
  Hyrax.config.iiif_image_url_builder.call(
29
34
  latest_file_id,
30
35
  base_url,
@@ -33,8 +38,10 @@ module Hyrax
33
38
  )
34
39
  end
35
40
 
36
- def iiif_endpoint(file_id, base_url: request.base_url)
41
+ def iiif_endpoint(file_id, base_url: nil)
37
42
  return unless Hyrax.config.iiif_image_server?
43
+ base_url ||= base_url_for_iiif
44
+
38
45
  IIIFManifest::IIIFEndpoint.new(
39
46
  Hyrax.config.iiif_info_url_builder.call(file_id, base_url),
40
47
  profile: Hyrax.config.iiif_image_compliance_level_uri
@@ -42,7 +49,7 @@ module Hyrax
42
49
  end
43
50
 
44
51
  def image_format(channels)
45
- channels&.include?('rgba') ? 'png' : 'jpg'
52
+ channels&.include?('rgba') ? 'image/png' : 'image/jpeg'
46
53
  end
47
54
 
48
55
  ##
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module DisplaysTranscripts
4
+ extend ActiveSupport::Concern
5
+
6
+ # @return [Array<SolrDocument>] the solr documents represented by
7
+ # the audio/video file set's transcript_ids
8
+ def transcripts
9
+ return [] if transcript_ids.blank?
10
+ @transcripts ||= begin
11
+ results = Hyrax::SolrQueryService.new
12
+ .accessible_by(
13
+ ability: (try(:current_ability) || ability),
14
+ action: :read
15
+ )
16
+ .with_ids(ids: transcript_ids)
17
+ .solr_documents
18
+ sort_transcripts_by_language(results)
19
+ end
20
+ end
21
+
22
+ def transcript_url(document, host: request.base_url, file_ext: "vtt")
23
+ Hyrax::Engine.routes.url_helpers.transcript_url(document.id, host: host, file_ext: file_ext)
24
+ end
25
+
26
+ # Try our best to convert language field to an ISO 639-1 code for use in the IIIF manifest.
27
+ # @param [Array<String>] - a solr document's language field. Parseable values include an ISO 639-1 code,
28
+ # an ISO 639-3 code, or the English name for a language
29
+ # Examples: https://github.com/scsmith/language_list#examples
30
+ # @return [String or NilClass] - the 2-letter code, or nil if no value or value is unparseable
31
+ def language_code(language)
32
+ return if language.empty?
33
+ value = language.first
34
+ if URI.parse(value).scheme
35
+ # This is probably a Library of Congress languages URI
36
+ # like http://id.loc.gov/vocabulary/iso639-3/eng, which can
37
+ # be configured with the Questioning Authority gem.
38
+ # Try to extract the code from the URI.
39
+ LanguageList::LanguageInfo.find(value.split("/").last).try(:iso_639_1)
40
+ else
41
+ # Otherwise, assume it is a language code or name and try
42
+ # to convert it to a 2-letter code
43
+ LanguageList::LanguageInfo.find(value).try(:iso_639_1)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def sort_transcripts_by_language(results)
50
+ current_locale = I18n.locale.to_s
51
+
52
+ # Sort alphabetically by language code
53
+ sorted = results.sort_by { |doc| language_code(doc.language) || '' }
54
+
55
+ # Move current locale to front
56
+ sorted.partition { |doc| language_code(doc.language) == current_locale }.flatten
57
+ end
58
+ end
59
+ end
@@ -6,6 +6,8 @@ module Hyrax
6
6
  include CharacterizationBehavior
7
7
  include WithEvents
8
8
  include DisplaysImage
9
+ include MissingMethodBehavior
10
+ include DisplaysTranscripts
9
11
 
10
12
  attr_accessor :solr_document, :current_ability, :request
11
13
 
@@ -18,29 +20,17 @@ module Hyrax
18
20
  @request = request
19
21
  end
20
22
 
21
- # CurationConcern methods
22
- delegate :stringify_keys, :human_readable_type, :collection?, :image?, :video?,
23
- :audio?, :pdf?, :office_document?, :representative_id, :to_s,
24
- :extensions_and_mime_types, to: :solr_document
25
-
26
- # Methods used by blacklight helpers
27
- delegate :has?, :first, :fetch, to: :solr_document
28
-
29
- # Metadata Methods
30
- delegate :title, :label, :description, :creator, :contributor, :subject,
31
- :publisher, :language, :date_uploaded,
32
- :embargo_release_date, :lease_expiration_date,
33
- :depositor, :keyword, :title_or_label, :keyword,
34
- :date_created, :date_modified, :itemtype,
35
- :original_file_id,
36
- to: :solr_document
37
-
23
+ delegate :to_s, to: :solr_document
38
24
  delegate :member_of_collection_ids, to: :parent
39
25
 
40
26
  def workflow
41
27
  nil
42
28
  end
43
29
 
30
+ def model
31
+ solr_document.to_model
32
+ end
33
+
44
34
  def single_use_links
45
35
  @single_use_links ||= SingleUseLink.where(item_id: id).map { |link| link_presenter_class.new(link) }
46
36
  end
@@ -109,7 +99,7 @@ module Hyrax
109
99
  ##
110
100
  # @return [Array<String>]
111
101
  def show_partials
112
- ['show_details']
102
+ %w[show_details metadata]
113
103
  end
114
104
 
115
105
  private
@@ -82,5 +82,44 @@ module Hyrax
82
82
  def title
83
83
  Array(object.try(:title)).sort.first || ""
84
84
  end
85
+
86
+ ##
87
+ # @return [String] a string representing the degree granting institution(s)
88
+ # as a semicolon delimited list
89
+ def degree_grantor
90
+ Array(object.try(:degree_grantor)).join('; ')
91
+ end
92
+
93
+ ##
94
+ # @return [String] a string representing the journal title
95
+ def journal_title
96
+ Array(object.try(:journal_title)).first || ''
97
+ end
98
+
99
+ ##
100
+ # @return [String] a string representing the journal volume
101
+ def volume
102
+ Array(object.try(:journal_volume)).first || ''
103
+ end
104
+
105
+ ##
106
+ # @return [String] a string representing the journal issue
107
+ def issue
108
+ Array(object.try(:journal_issue)).first || ''
109
+ end
110
+
111
+ ##
112
+ # @return [String] a string representing the first page
113
+ def first_page
114
+ Array(object.try(:page_start)).first || ''
115
+ end
116
+ alias firstpage first_page
117
+
118
+ ##
119
+ # @return [String] a string representing the last page
120
+ def last_page
121
+ Array(object.try(:page_end)).first || ''
122
+ end
123
+ alias lastpage last_page
85
124
  end
86
125
  end
@@ -63,7 +63,7 @@ module Hyrax
63
63
  ##
64
64
  # @return [Array<DisplayImagePresenter>]
65
65
  def file_set_presenters
66
- member_presenters.select(&:file_set?)
66
+ member_presenters.select { |p| p.file_set? && (p.display_image || p.display_content) }
67
67
  end
68
68
 
69
69
  ##
@@ -119,14 +119,29 @@ module Hyrax
119
119
  ##
120
120
  # @return [Array<Hash{String => String}>]
121
121
  def sequence_rendering
122
- Array(try(:rendering_ids)).map do |file_set_id|
123
- rendering = file_set_presenters.find { |p| p.id == file_set_id }
122
+ Array(try(:rendering_ids)).filter_map do |file_set_id|
123
+ rendering = member_presenters.find { |p| p.file_set? && p.id == file_set_id }
124
124
  next unless rendering
125
125
 
126
126
  { '@id' => Hyrax::Engine.routes.url_helpers.download_url(rendering.id, host: hostname),
127
127
  'format' => rendering.mime_type.presence || I18n.t("hyrax.manifest.unknown_mime_text"),
128
128
  'label' => I18n.t("hyrax.manifest.download_text") + (rendering.label || '') }
129
- end.flatten
129
+ end
130
+ end
131
+
132
+ ##
133
+ # Provides a link to the work page as the homepage for the object
134
+ # represented by the IIIF manifest (see
135
+ # https://iiif.io/api/cookbook/recipe/0047-homepage/).
136
+ # This can be helpful if the IIIF manifest is reused on an external site.
137
+ # @return [Array<Hash{String => String}>]
138
+ def homepage
139
+ [{
140
+ 'id' => Rails.application.routes.url_helpers.polymorphic_url(model, host: hostname),
141
+ 'type' => 'Text',
142
+ 'format' => 'text/html',
143
+ 'label' => { 'none' => [Array(title).first || ''] }
144
+ }]
130
145
  end
131
146
 
132
147
  ##
@@ -188,6 +203,8 @@ module Hyrax
188
203
  delegate_all
189
204
 
190
205
  include Hyrax::DisplaysImage
206
+ include Hyrax::DisplaysContent
207
+ include Hyrax::AnnotatesContent
191
208
 
192
209
  ##
193
210
  # @!attribute [w] ability
@@ -201,6 +218,7 @@ module Hyrax
201
218
  #
202
219
  # @return [IIIFManifest::DisplayImage] the display image required by the manifest builder.
203
220
  def display_image
221
+ return nil if Hyrax.config.iiif_manifest_factory == ::IIIFManifest::V3::ManifestFactory
204
222
  return nil unless model.image?
205
223
  return nil unless latest_file_id
206
224
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module MissingMethodBehavior
4
+ private
5
+
6
+ def method_missing(method_name, *args, &block)
7
+ return solr_document.public_send(method_name, *args, &block) if solr_document.respond_to?(method_name)
8
+ super
9
+ end
10
+
11
+ def respond_to_missing?(method_name, include_private = false)
12
+ solr_document.respond_to?(method_name, include_private) || super
13
+ end
14
+ end
15
+ end