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
@@ -30,6 +30,10 @@ module Hyrax
30
30
  @ordered_member_ids ||= valkyrie? ? member_ids : query_for_ordered_ids
31
31
  end
32
32
 
33
+ def flexible?
34
+ respond_to?(:schema_version) && schema_version.present?
35
+ end
36
+
33
37
  private
34
38
 
35
39
  def query_for_ordered_ids(limit: 10_000,
@@ -12,6 +12,8 @@ module Hyrax
12
12
  # end
13
13
  #
14
14
  # @see https://github.com/projectblacklight/blacklight/wiki/Understanding-Rails-and-Blacklight#models
15
+
16
+ # rubocop:disable Metrics/ModuleLength
15
17
  module SolrDocumentBehavior
16
18
  ModelWrapper = ActiveFedoraDummyModel # alias for backward compatibility
17
19
 
@@ -82,9 +84,15 @@ module Hyrax
82
84
 
83
85
  # Method to return the model
84
86
  def hydra_model(classifier: nil)
85
- model = first('has_model_ssim')&.safe_constantize
86
- model = (first('has_model_ssim')&.+ 'Resource')&.safe_constantize if Hyrax.config.valkyrie_transition?
87
- model || model_classifier(classifier).classifier(self).best_model
87
+ valkyrie_model = Valkyrie.config.resource_class_resolver.call(hydra_model_name) if Hyrax.config.valkyrie_transition?
88
+
89
+ valkyrie_model ||
90
+ hydra_model_name&.safe_constantize ||
91
+ model_classifier(classifier).classifier(self).best_model
92
+ end
93
+
94
+ def hydra_model_name
95
+ @has_model ||= first('has_model_ssim')
88
96
  end
89
97
 
90
98
  def depositor(default = '')
@@ -146,10 +154,27 @@ module Hyrax
146
154
  JSON.parse(self['extensions_and_mime_types_ssm'].first).map(&:with_indifferent_access) if self['extensions_and_mime_types_ssm']
147
155
  end
148
156
 
157
+ def schema_version
158
+ self['schema_version_ssi']
159
+ end
160
+
161
+ def contexts
162
+ self['contexts_ssim']
163
+ end
164
+
165
+ def flexible?
166
+ schema_version.present?
167
+ end
168
+
169
+ def transcript_ids
170
+ self['transcript_ids_ssim']
171
+ end
172
+
149
173
  private
150
174
 
151
175
  def model_classifier(classifier)
152
176
  classifier || ActiveFedora.model_mapper
153
177
  end
154
178
  end
179
+ # rubocop:enable Metrics/ModuleLength
155
180
  end
@@ -6,7 +6,7 @@ module Hyrax
6
6
 
7
7
  included do
8
8
  # This holds the workflow state
9
- property :state, predicate: Vocab::FedoraResourceStatus.objState, multiple: false
9
+ property :state, predicate: Vocab::FedoraResourceStatus.objState, multiple: false if respond_to?(:property)
10
10
  end
11
11
 
12
12
  ##
@@ -50,7 +50,7 @@ module Hyrax
50
50
  # Hyrax::ValkyrieLazyMigration.migrating(self, from: MyWork)
51
51
  # end
52
52
  def self.migrating(klass, from:, name_class: Hyrax::ValkyrieLazyMigration::ResourceName)
53
- Wings::ModelRegistry.register(klass, from)
53
+ Wings::ModelRegistry.register(klass, from) if defined?(Wings::ModelRegistry)
54
54
  from.singleton_class.define_method(:migrating_from) { from }
55
55
  from.singleton_class.define_method(:migrating_to) { klass }
56
56
  klass.singleton_class.define_method(:migrating_from) { from }
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module WithEmbargoesAndLeases
4
+ extend ActiveSupport::Concern
5
+
6
+ def embargo=(value)
7
+ raise TypeError "can't convert #{value.class} into Hyrax::Embargo" unless value.is_a? Hyrax::Embargo
8
+
9
+ @embargo = value
10
+ self.embargo_id = @embargo.id
11
+ end
12
+
13
+ def embargo
14
+ return @embargo if @embargo
15
+ @embargo = Hyrax.query_service.find_by(id: embargo_id) if embargo_id.present?
16
+ end
17
+
18
+ def lease=(value)
19
+ raise TypeError "can't convert #{value.class} into Hyrax::Lease" unless value.is_a? Hyrax::Lease
20
+
21
+ @lease = value
22
+ self.lease_id = @lease.id
23
+ end
24
+
25
+ def lease
26
+ return @lease if @lease
27
+ @lease = Hyrax.query_service.find_by(id: lease_id) if lease_id.present?
28
+ end
29
+ end
30
+ end
@@ -34,6 +34,10 @@ module Hyrax
34
34
  self.class.to_rdf_representation
35
35
  end
36
36
 
37
+ def flexible?
38
+ false
39
+ end
40
+
37
41
  module ClassMethods
38
42
  # This governs which partial to draw when you render this type of object
39
43
  def _to_partial_path # :nodoc:
@@ -43,6 +47,10 @@ module Hyrax
43
47
  "hyrax/#{collection}/#{element}"
44
48
  end
45
49
  end
50
+
51
+ def flexible?
52
+ false
53
+ end
46
54
  end
47
55
  end
48
56
  end
@@ -25,7 +25,7 @@ module Hyrax
25
25
  # @see Valkyrie query adapter's #find_inverse_references_by
26
26
  #
27
27
  class AdministrativeSet < Hyrax::Resource
28
- include Hyrax::Schema(:core_metadata)
28
+ include Hyrax::Schema(:core_metadata) if Hyrax.config.admin_set_include_metadata?
29
29
 
30
30
  attribute :alternative_title, Valkyrie::Types::Set.of(Valkyrie::Types::String)
31
31
  attribute :creator, Valkyrie::Types::Set.of(Valkyrie::Types::String)
@@ -13,7 +13,7 @@ module Hyrax
13
13
  # @example
14
14
  # Hyrax::ChangeSet(Monograph)
15
15
  def self.ChangeSet(resource_class)
16
- klass = (resource_class.to_s + "ChangeSet").safe_constantize || Hyrax::ChangeSet
16
+ klass = (resource_class.name + "ChangeSet").safe_constantize || Hyrax::ChangeSet
17
17
  Class.new(klass) do
18
18
  (resource_class.fields - resource_class.reserved_attributes).each do |field|
19
19
  property field, default: nil
@@ -29,6 +29,8 @@ module Hyrax
29
29
  end
30
30
 
31
31
  class ChangeSet < Valkyrie::ChangeSet
32
+ validates_with Hyrax::ControlledVocabularyValidator
33
+
32
34
  ##
33
35
  # @api public
34
36
  #
@@ -14,8 +14,10 @@ module Hyrax
14
14
  attribute :embargo_release_date, Valkyrie::Types::DateTime
15
15
  attribute :embargo_history, Valkyrie::Types::Array
16
16
 
17
+ # Fix releasing embargos on the day they are expired - this solves a 1 second bug around how
18
+ # midnights are calculated, which causes day of embargos to incorrectly set the permissions to private
17
19
  def active?
18
- (embargo_release_date.present? && Hyrax::TimeService.time_in_utc < embargo_release_date)
20
+ (embargo_release_date.present? && Date.yesterday.end_of_day < embargo_release_date)
19
21
  end
20
22
  end
21
23
  end
@@ -44,16 +44,31 @@ module Hyrax
44
44
 
45
45
  # @return [Array<RDF::URI>] list of all uses
46
46
  def use_list
47
- [ORIGINAL_FILE,
48
- THUMBNAIL_IMAGE,
49
- EXTRACTED_TEXT,
50
- INTERMEDIATE_FILE,
51
- PRESERVATION_FILE,
52
- SERVICE_FILE,
53
- TRANSCRIPT]
47
+ [
48
+ EXTRACTED_TEXT,
49
+ INTERMEDIATE_FILE,
50
+ ORIGINAL_FILE,
51
+ PRESERVATION_FILE,
52
+ SERVICE_FILE,
53
+ THUMBNAIL_IMAGE,
54
+ TRANSCRIPT
55
+ ]
54
56
  end
55
57
  module_function :use_list
56
58
 
59
+ def keys
60
+ [
61
+ :extracted_file,
62
+ :intermediate_file,
63
+ :original_file,
64
+ :preservation_file,
65
+ :service_file,
66
+ :thumbnail_file,
67
+ :transcript_file
68
+ ]
69
+ end
70
+ module_function :keys
71
+
57
72
  ##
58
73
  # @param use [RDF::URI, Symbol]
59
74
  #
@@ -49,8 +49,10 @@ module Hyrax
49
49
  # @see Hyrax::CustomQueries::Navigators::ParentWorkNavigator#find_parent_work
50
50
  # @see https://wiki.duraspace.org/display/samvera/Hydra%3A%3AWorks+Shared+Modeling
51
51
  class FileSet < Hyrax::Resource
52
- include Hyrax::Schema(:core_metadata)
53
- include Hyrax::Schema(:file_set_metadata)
52
+ if Hyrax.config.file_set_include_metadata?
53
+ include Hyrax::Schema(:core_metadata)
54
+ include Hyrax::Schema(:file_set_metadata)
55
+ end
54
56
 
55
57
  def self.model_name(name_class: Hyrax::Name)
56
58
  @_model_name ||= name_class.new(self, nil, 'FileSet')
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+ # rubocop:disable Metrics/ClassLength
3
+ class Hyrax::FlexibleSchema < ApplicationRecord
4
+ serialize :profile, coder: YAML
5
+ serialize :contexts, coder: YAML
6
+
7
+ validate :validate_profile
8
+ validate :validate_property_name_conflicts
9
+
10
+ before_save :update_contexts
11
+
12
+ def warnings
13
+ @warnings ||= ActiveModel::Errors.new(self)
14
+ end
15
+
16
+ def self.current_version
17
+ order("created_at asc").last&.profile
18
+ end
19
+
20
+ def self.current_schema_id
21
+ order("created_at asc").last&.id
22
+ end
23
+
24
+ def self.create_default_schema
25
+ m3_profile_path = Hyrax::Schema.m3_schema_loader.config_paths&.first
26
+ raise ArgumentError, "No M3 profile found, check the Hyrax.config.schema_loader_config_search_paths" unless m3_profile_path
27
+ schema = Hyrax::FlexibleSchema.first
28
+ return if schema
29
+ schema = Hyrax::FlexibleSchema.new(profile: YAML.safe_load_file(m3_profile_path))
30
+ schema.save(validate: false)
31
+ schema
32
+ end
33
+
34
+ # Retrieve the properties for the model / work type
35
+ # This is a class method called by the model at class load
36
+ # meaning AdminSet is not available and we cannot get the
37
+ # contextual dynamic_schema
38
+ # Instead we use the default (contextless) dynamic_schema
39
+ # which will add all properties available for that class
40
+ # @return [Array] property#to_sym
41
+ def self.default_properties
42
+ current_version['properties'].symbolize_keys!.keys
43
+ rescue StandardError
44
+ []
45
+ end
46
+
47
+ # Retrieve the required data to use for mappings
48
+ def self.mappings_data_for(mapping = 'simple_dc_pmh')
49
+ # for OAI-PMH we need the mappings and indexing info
50
+ # for properties with the specified mapping
51
+ return {} unless current_version
52
+ current_version['properties'].each_with_object({}) do |(key, values), obj|
53
+ next unless values['mappings'] && values['mappings'][mapping]
54
+ obj[key] = {
55
+ 'indexing' => values['indexing'],
56
+ 'mappings' => { mapping => values['mappings'][mapping] }
57
+ }
58
+ end
59
+ end
60
+
61
+ def update_contexts
62
+ self.contexts = profile['contexts']
63
+ end
64
+
65
+ def title
66
+ "#{profile['profile']['responsibility_statement']} - version #{id}"
67
+ end
68
+
69
+ def attributes_for(class_name)
70
+ class_names[class_name]
71
+ end
72
+
73
+ def schema_version
74
+ profile['m3_version']
75
+ end
76
+
77
+ def context_select
78
+ contexts&.map { |k, v| [v&.[]('display_label'), k] }
79
+ end
80
+
81
+ def metadata_profile_type
82
+ profile['profile']['type']
83
+ end
84
+
85
+ def version
86
+ id
87
+ end
88
+
89
+ def profile_created_at
90
+ created_at.strftime("%b %d, %Y")
91
+ end
92
+
93
+ private
94
+
95
+ def validate_profile
96
+ validation_service = Hyrax::FlexibleSchemaValidatorService.new(profile:)
97
+ validation_service.validate!
98
+
99
+ validation_service.errors.each do |e|
100
+ errors.add(:profile, e.to_s)
101
+ end
102
+
103
+ validation_service.warnings.each do |w|
104
+ warnings.add(:profile, "Warning: #{w.to_s}")
105
+ end
106
+ end
107
+
108
+ def validate_property_name_conflicts
109
+ return unless profile&.dig('properties')
110
+
111
+ # Group properties by their resolved name
112
+ properties_by_name = profile['properties'].each_with_object({}) do |(key, config), hash|
113
+ property_name = config['name'] || key
114
+ hash[property_name] ||= []
115
+ hash[property_name] << { key: key, config: config }
116
+ end
117
+
118
+ # Check for conflicts (same name with overlapping class/context)
119
+ properties_by_name.each do |property_name, properties|
120
+ next if properties.length == 1
121
+
122
+ # Check all pairs for conflicts
123
+ properties.combination(2).each do |prop1, prop2|
124
+ if properties_conflict?(prop1[:config], prop2[:config])
125
+ errors.add(:profile, "Property name '#{property_name}' conflicts between '#{prop1[:key]}' and '#{prop2[:key]}' - they have overlapping classes and contexts")
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def properties_conflict?(config1, config2)
132
+ classes1 = Array(config1.dig('available_on', 'class'))
133
+ classes2 = Array(config2.dig('available_on', 'class'))
134
+
135
+ contexts1 = Array(config1.dig('available_on', 'context'))
136
+ contexts2 = Array(config2.dig('available_on', 'context'))
137
+
138
+ # If no contexts specified, consider as universal context
139
+ contexts1 = [nil] if contexts1.empty?
140
+ contexts2 = [nil] if contexts2.empty?
141
+
142
+ # Conflict if there's any overlap in both classes AND contexts
143
+ class_overlap = (classes1 & classes2).any?
144
+ context_overlap = !(contexts1 & contexts2).empty?
145
+
146
+ class_overlap && context_overlap
147
+ end
148
+
149
+ def class_names
150
+ return @class_names if @class_names
151
+ @class_names = {}
152
+ profile['classes'].keys.each do |class_name|
153
+ @class_names[class_name] = {}
154
+ end
155
+ profile['properties'].each do |key, values|
156
+ property_name = values['name'] || key
157
+ values['available_on']['class'].each do |property_class|
158
+ # map some m3 items to what Hyrax expects
159
+ values = values_map(values)
160
+ @class_names[property_class][property_name] = values
161
+ end
162
+ end
163
+ @class_names
164
+ end
165
+
166
+ def values_map(values)
167
+ values['type'] = lookup_type(values['range'])
168
+ values['predicate'] = values['property_uri']
169
+ values['index_keys'] = values['indexing']
170
+ values['context'] = values.dig('available_on', 'context')
171
+ values['multiple'] = determine_multiplicity(values)
172
+
173
+ normalize_form_attributes(values)
174
+
175
+ values
176
+ end
177
+
178
+ def determine_multiplicity(values)
179
+ return values['data_type'] == 'array' if values.key?('data_type')
180
+ return values['multi_value'] if values.key?('multi_value')
181
+
182
+ if (card = values['cardinality'])
183
+ max = card['maximum']
184
+ return max.nil? || max.to_i > 1
185
+ end
186
+
187
+ false
188
+ end
189
+
190
+ def normalize_form_attributes(values)
191
+ return unless values['form']
192
+
193
+ # Rename `multi_value` key to `multiple` (legacy support)
194
+ values['form']['multiple'] = values['form'].delete('multi_value') if values['form'].key?('multi_value')
195
+
196
+ values['form']['multiple'] = values['form'].delete('data_type') == 'array' if values['form'].key?('data_type')
197
+
198
+ assign_required_flag(values)
199
+ end
200
+
201
+ def assign_required_flag(values)
202
+ return unless (card = values['cardinality']) && card['minimum']
203
+
204
+ return if values['form'].key?('required')
205
+
206
+ required_flag = card['minimum'].to_i.positive?
207
+ values['form']['required'] = required_flag
208
+ end
209
+
210
+ def lookup_type(range)
211
+ case range
212
+ when "http://www.w3.org/2001/XMLSchema#dateTime"
213
+ 'date_time'
214
+ else
215
+ range.split('#').last.underscore
216
+ end
217
+ end
218
+ end
219
+ # rubocop:enable Metrics/ClassLength
@@ -14,8 +14,10 @@ module Hyrax
14
14
  attribute :lease_expiration_date, Valkyrie::Types::DateTime
15
15
  attribute :lease_history, Valkyrie::Types::Array
16
16
 
17
+ # Fix releasing leases on the day they are expired - this solves a 1 second bug around how
18
+ # midnights are calculated, which causes day of leases to incorrectly set the permissions to private
17
19
  def active?
18
- (lease_expiration_date.present? && Hyrax::TimeService.time_in_utc < lease_expiration_date)
20
+ (lease_expiration_date.present? && Time.zone.today.end_of_day < lease_expiration_date)
19
21
  end
20
22
  end
21
23
  end
@@ -40,7 +40,10 @@ module Hyrax
40
40
  # @see Hyrax::CustomQueries::Navigators::CollectionMembers#find_members_of
41
41
  #
42
42
  class PcdmCollection < Hyrax::Resource
43
- include Hyrax::Schema(:core_metadata)
43
+ include Hyrax::Schema(:core_metadata) if Hyrax.config.collection_include_metadata?
44
+ # See documentation/redirects.md for the redirects feature.
45
+ include Hyrax::Schema(:redirects) if Hyrax.config.collection_include_metadata? && Hyrax.config.redirects_enabled?
46
+ include Hyrax::RedirectsNormalization if Hyrax.config.redirects_enabled?
44
47
 
45
48
  attribute :collection_type_gid, Valkyrie::Types::String
46
49
  attribute :member_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID).meta(ordered: true)
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ ##
5
+ # Wraps a single redirect entry for use in form views, providing `.path`
6
+ # and `.is_display_url` readers over the underlying persisted hash.
7
+ #
8
+ # Redirects are persisted as plain hashes on the parent work or
9
+ # collection. Form-render code calls `Hyrax::Redirect.wrap(entry)` to
10
+ # get a value object the view can call methods on. Other code (the
11
+ # validator, indexer, sync step) reads the persisted hash directly.
12
+ #
13
+ # @example
14
+ # Hyrax::Redirect.new(path: '/handle/12345/678', is_display_url: false)
15
+ # Hyrax::Redirect.wrap('path' => '/foo', 'is_display_url' => true)
16
+ class Redirect
17
+ attr_reader :path, :is_display_url
18
+
19
+ ##
20
+ # Accept nil values so the view can build an empty trailing row.
21
+ def initialize(path: nil, is_display_url: false)
22
+ @path = path
23
+ @is_display_url = is_display_url
24
+ end
25
+
26
+ ##
27
+ # Build a presenter from a hash. If passed a presenter, returns it
28
+ # unchanged. Returns nil for nil input. Accepts string or symbol keys.
29
+ #
30
+ # @param input [Hyrax::Redirect, Hash, nil]
31
+ # @return [Hyrax::Redirect, nil]
32
+ def self.wrap(input)
33
+ return nil if input.nil?
34
+ return input if input.is_a?(Hyrax::Redirect)
35
+ raise ArgumentError, "cannot wrap #{input.class} as Hyrax::Redirect" unless input.respond_to?(:to_h)
36
+
37
+ h = input.to_h.transform_keys(&:to_s)
38
+ new(path: h['path'], is_display_url: h.fetch('is_display_url', false))
39
+ end
40
+
41
+ ##
42
+ # @return [Hash{String => Object}] string-keyed hash matching the persisted shape.
43
+ def to_h
44
+ { 'path' => path, 'is_display_url' => is_display_url }
45
+ end
46
+
47
+ def as_json(*)
48
+ to_h
49
+ end
50
+
51
+ ##
52
+ # Equality on attribute values, so `Array#uniq` works as expected.
53
+ def ==(other)
54
+ other.is_a?(Hyrax::Redirect) &&
55
+ other.path == path &&
56
+ other.is_display_url == is_display_url
57
+ end
58
+ alias eql? ==
59
+
60
+ def hash
61
+ [path, is_display_url].hash
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ # ActiveRecord-backed redirects table for global path uniqueness.
5
+ #
6
+ # Maintained by Hyrax::Transactions::Steps::SyncRedirectPaths and
7
+ # Hyrax::Transactions::Steps::RemoveRedirectPaths; queried by
8
+ # Hyrax::RedirectsLookup. The unique index on `from_path` is the source
9
+ # of truth for "no two records share a redirect alias"; this class just
10
+ # exposes it.
11
+ class RedirectPath < ActiveRecord::Base
12
+ self.table_name = 'hyrax_redirect_paths'
13
+ end
14
+ end
@@ -30,9 +30,11 @@ module Hyrax
30
30
  # `Hyrax::VisibilityWriter` (which provide their underlying
31
31
  # implementations).
32
32
  #
33
- class Resource < Valkyrie::Resource
33
+ class Resource < Valkyrie::Resource # disable:rubocop Metrics/ClassLength
34
34
  include Hyrax::Naming
35
35
  include Hyrax::WithEvents
36
+ include Hyrax::WithEmbargoesAndLeases
37
+ include Hyrax::Suppressible
36
38
 
37
39
  attribute :alternate_ids, Valkyrie::Types::Array.of(Valkyrie::Types::ID)
38
40
  attribute :embargo_id, Valkyrie::Types::Params::ID
@@ -44,6 +46,21 @@ module Hyrax
44
46
  :read_users, :read_users=, to: :permission_manager
45
47
 
46
48
  class << self
49
+ def inherited(subclass)
50
+ super
51
+ subclass.acts_as_flexible_resource if Hyrax.config.flexible_classes.include?(subclass.name)
52
+ end
53
+
54
+ def acts_as_flexible_resource
55
+ include Hyrax::Flexibility
56
+ include Hyrax::Schema(name, schema_loader: Hyrax::Schema.m3_schema_loader)
57
+ Hyrax.config.flexible_classes << name unless Hyrax.config.flexible_classes.include?(name)
58
+ end
59
+
60
+ def flexible?
61
+ defined?(super) ? super : false
62
+ end
63
+
47
64
  ##
48
65
  # @return [String] a human readable name for the model
49
66
  def human_readable_type
@@ -105,6 +122,10 @@ module Hyrax
105
122
  end
106
123
  end
107
124
 
125
+ def flexible?
126
+ self.class.flexible?
127
+ end
128
+
108
129
  ##
109
130
  # @return [Boolean]
110
131
  def collection?
@@ -170,30 +191,6 @@ module Hyrax
170
191
  visibility_reader.read
171
192
  end
172
193
 
173
- def embargo=(value)
174
- raise TypeError "can't convert #{value.class} into Hyrax::Embargo" unless value.is_a? Hyrax::Embargo
175
-
176
- @embargo = value
177
- self.embargo_id = @embargo.id
178
- end
179
-
180
- def embargo
181
- return @embargo if @embargo
182
- @embargo = Hyrax.query_service.find_by(id: embargo_id) if embargo_id.present?
183
- end
184
-
185
- def lease=(value)
186
- raise TypeError "can't convert #{value.class} into Hyrax::Lease" unless value.is_a? Hyrax::Lease
187
-
188
- @lease = value
189
- self.lease_id = @lease.id
190
- end
191
-
192
- def lease
193
- return @lease if @lease
194
- @lease = Hyrax.query_service.find_by(id: lease_id) if lease_id.present?
195
- end
196
-
197
194
  protected
198
195
 
199
196
  def visibility_writer
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ if defined?(::Riiif::File)
3
+ module Hyrax
4
+ module Riiif
5
+ class File < ::Riiif::File
6
+ include ActiveSupport::Benchmarkable
7
+
8
+ attr_reader :id
9
+
10
+ def initialize(input_path, tempfile = nil, id:)
11
+ super(input_path, tempfile)
12
+ raise(ArgumentError, "must specify id") if id.blank?
13
+ @id = id
14
+ end
15
+
16
+ # Wrap extract in a read lock and benchmark it
17
+ def extract(transformation, image_info = nil)
18
+ ::Riiif::Image.file_resolver.file_locks[id].with_read_lock do
19
+ benchmark "Hyrax::Riiif::File extracted #{path} with #{transformation.to_params}", level: :debug do
20
+ super
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def logger
28
+ Hyrax.logger
29
+ end
30
+ end
31
+ end
32
+ end
33
+ else
34
+ module Hyrax
35
+ module Riiif
36
+ class File
37
+ def initialize(*)
38
+ raise 'Riiif not available'
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end