hyrax 5.2.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 (527) hide show
  1. checksums.yaml +4 -4
  2. data/.dassie/.env +5 -1
  3. data/.dassie/Gemfile +4 -2
  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/browse_everything_providers.yml +1 -1
  25. data/.dassie/config/bulkrax_api.yml +86 -0
  26. data/.dassie/config/initializers/bulkrax.rb +92 -0
  27. data/.dassie/config/initializers/clamav.rb +2 -0
  28. data/.dassie/config/initializers/hyrax.rb +7 -1
  29. data/.dassie/config/initializers/riiif.rb +4 -80
  30. data/.dassie/config/initializers/wings.rb +1 -1
  31. data/.dassie/config/metadata_profiles/m3_profile.yaml +929 -0
  32. data/.dassie/config/puma.rb +4 -2
  33. data/.dassie/config/routes.rb +7 -0
  34. data/.dassie/config/sidekiq.yml +17 -0
  35. data/.dassie/config/uv/uv.html +63 -81
  36. data/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  37. data/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  38. data/.dassie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  39. data/.dassie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  40. data/.dassie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  41. data/.dassie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  42. data/.dassie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  43. data/.dassie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  44. data/.dassie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  45. data/.dassie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  46. data/.dassie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  47. data/.dassie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  48. data/.dassie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  49. data/.dassie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  50. data/.dassie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  51. data/.dassie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  52. data/.dassie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  53. data/.dassie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  54. data/.dassie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  55. data/.dassie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  56. data/.dassie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  57. data/.dassie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  58. data/.dassie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  59. data/.dassie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  60. data/.dassie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  61. data/.dassie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  62. data/.dassie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  63. data/.dassie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  64. data/.dassie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  65. data/.dassie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  66. data/.dassie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  67. data/.dassie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  68. data/.dassie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  69. data/.dassie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  70. data/.dassie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  71. data/.dassie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  72. data/.dassie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  73. data/.dassie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  74. data/.dassie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  75. data/.dassie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  76. data/.dassie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  77. data/.dassie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  78. data/.dassie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  79. data/.dassie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  80. data/.dassie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  81. data/.dassie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  82. data/.dassie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  83. data/.dassie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  84. data/.dassie/db/schema.rb +154 -1
  85. data/.dassie/package.json +1 -1
  86. data/.dassie/rspec_split_configuration.json +835 -0
  87. data/.dassie/solr/conf/solrconfig.xml +21 -5
  88. data/.github/{ISSUE_TEMPLATE.md → ISSUE_TEMPLATE/issue_template.md} +5 -0
  89. data/.github/workflows/lint-build-test.yml +5 -1
  90. data/.github/workflows/release-charts.yml +48 -0
  91. data/.gitignore +6 -0
  92. data/.koppie/.env +5 -1
  93. data/.koppie/Gemfile +3 -1
  94. data/.koppie/app/assets/images/bulkrax/removed.png +0 -0
  95. data/.koppie/app/assets/javascripts/application.js +2 -0
  96. data/.koppie/app/assets/stylesheets/application.css +1 -0
  97. data/.koppie/app/controllers/catalog_controller.rb +1 -1
  98. data/.koppie/app/forms/collection_resource_form.rb +5 -2
  99. data/.koppie/app/forms/file_set_form.rb +5 -0
  100. data/.koppie/app/forms/generic_work_form.rb +5 -3
  101. data/.koppie/app/forms/monograph_form.rb +5 -3
  102. data/.koppie/app/indexers/collection_resource_indexer.rb +5 -2
  103. data/.koppie/app/indexers/file_set_indexer.rb +7 -0
  104. data/.koppie/app/indexers/generic_work_indexer.rb +6 -3
  105. data/.koppie/app/indexers/monograph_indexer.rb +6 -2
  106. data/.koppie/app/models/ability.rb +8 -0
  107. data/.koppie/app/models/collection_resource.rb +4 -2
  108. data/.koppie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
  109. data/.koppie/app/models/generic_work.rb +5 -2
  110. data/.koppie/app/models/monograph.rb +5 -2
  111. data/.koppie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  112. data/.koppie/bin/importer +142 -0
  113. data/.koppie/bin/web +4 -0
  114. data/.koppie/config/browse_everything_providers.yml +2 -0
  115. data/.koppie/config/bulkrax_api.yml +86 -0
  116. data/.koppie/config/initializers/bulkrax.rb +92 -0
  117. data/.koppie/config/initializers/clamav.rb +2 -0
  118. data/.koppie/config/initializers/hyrax.rb +11 -3
  119. data/.koppie/config/initializers/riiif.rb +4 -82
  120. data/.koppie/config/metadata_profiles/m3_profile.yaml +930 -0
  121. data/.koppie/config/routes.rb +7 -0
  122. data/.koppie/config/sidekiq.yml +2 -0
  123. data/.koppie/config/uv/uv.html +63 -81
  124. data/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
  125. data/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
  126. data/.koppie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
  127. data/.koppie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
  128. data/.koppie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
  129. data/.koppie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
  130. data/.koppie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
  131. data/.koppie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
  132. data/.koppie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
  133. data/.koppie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
  134. data/.koppie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
  135. data/.koppie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
  136. data/.koppie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
  137. data/.koppie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
  138. data/.koppie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
  139. data/.koppie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
  140. data/.koppie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
  141. data/.koppie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
  142. data/.koppie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
  143. data/.koppie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
  144. data/.koppie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
  145. data/.koppie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
  146. data/.koppie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
  147. data/.koppie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
  148. data/.koppie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
  149. data/.koppie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
  150. data/.koppie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
  151. data/.koppie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
  152. data/.koppie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
  153. data/.koppie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
  154. data/.koppie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
  155. data/.koppie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
  156. data/.koppie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
  157. data/.koppie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
  158. data/.koppie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
  159. data/.koppie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
  160. data/.koppie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
  161. data/.koppie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
  162. data/.koppie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
  163. data/.koppie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
  164. data/.koppie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
  165. data/.koppie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
  166. data/.koppie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
  167. data/.koppie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
  168. data/.koppie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
  169. data/.koppie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
  170. data/.koppie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
  171. data/.koppie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
  172. data/.koppie/db/schema.rb +154 -1
  173. data/.koppie/package.json +1 -1
  174. data/.koppie/rspec_split_configuration.json +835 -0
  175. data/.koppie/solr/conf/solrconfig.xml +0 -5
  176. data/.koppie/yarn.lock +5587 -752
  177. data/.rubocop.yml +1 -0
  178. data/CONTAINERS.md +2 -0
  179. data/Dockerfile +9 -22
  180. data/Gemfile +0 -1
  181. data/Gemfile.allinson +2 -0
  182. data/README.md +1 -2
  183. data/app/actors/hyrax/actors/file_actor.rb +2 -0
  184. data/app/actors/hyrax/actors/file_set_actor.rb +1 -1
  185. data/app/assets/javascripts/hyrax/app.js.erb +143 -10
  186. data/app/assets/javascripts/hyrax/collection_select.js +68 -0
  187. data/app/assets/javascripts/hyrax/copy_permalink_button.js +28 -0
  188. data/app/assets/javascripts/hyrax/redirects.js +45 -0
  189. data/app/assets/javascripts/hyrax/relationships/control.es6 +21 -1
  190. data/app/assets/javascripts/hyrax/select_work_type.es6 +7 -2
  191. data/app/assets/javascripts/hyrax.js +3 -1
  192. data/app/assets/stylesheets/hyrax/_file-show.scss +1 -0
  193. data/app/assets/stylesheets/hyrax/_viewer.scss +8 -0
  194. data/app/assets/stylesheets/hyrax/dashboard.scss +22 -1
  195. data/app/assets/stylesheets/hyrax/sidebar.scss +98 -3
  196. data/app/authorities/qa/authorities/collections.rb +9 -9
  197. data/app/controllers/concerns/hyrax/analytics_error_handling.rb +97 -0
  198. data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +3 -1
  199. data/app/controllers/concerns/hyrax/ensure_migrated_behavior.rb +50 -0
  200. data/app/controllers/concerns/hyrax/flexible_catalog_behavior.rb +206 -0
  201. data/app/controllers/concerns/hyrax/flexible_schema_behavior.rb +17 -0
  202. data/app/controllers/concerns/hyrax/redirect_to_display_url.rb +54 -0
  203. data/app/controllers/concerns/hyrax/works_controller_behavior.rb +52 -10
  204. data/app/controllers/hyrax/admin/admin_sets_controller.rb +21 -13
  205. data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -0
  206. data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +1 -0
  207. data/app/controllers/hyrax/admin/metadata_profiles_controller.rb +66 -0
  208. data/app/controllers/hyrax/batch_uploads_controller.rb +2 -0
  209. data/app/controllers/hyrax/dashboard/collections_controller.rb +27 -6
  210. data/app/controllers/hyrax/dashboard/nest_collections_controller.rb +2 -1
  211. data/app/controllers/hyrax/dashboard_controller.rb +2 -1
  212. data/app/controllers/hyrax/file_sets_controller.rb +19 -1
  213. data/app/controllers/hyrax/homepage_controller.rb +7 -0
  214. data/app/controllers/hyrax/my/works_controller.rb +2 -21
  215. data/app/controllers/hyrax/permissions_controller.rb +4 -2
  216. data/app/controllers/hyrax/redirects_controller.rb +56 -0
  217. data/app/controllers/hyrax/single_use_links_viewer_controller.rb +2 -1
  218. data/app/controllers/hyrax/transcripts_controller.rb +31 -0
  219. data/app/controllers/hyrax/uploads_controller.rb +18 -9
  220. data/app/forms/concerns/hyrax/based_near_field_behavior.rb +77 -0
  221. data/app/forms/concerns/hyrax/flexible_form_behavior.rb +37 -0
  222. data/app/forms/concerns/hyrax/redirects_field_behavior.rb +95 -0
  223. data/app/forms/concerns/hyrax/transcripts_behavior.rb +40 -0
  224. data/app/forms/hyrax/forms/admin_set_form.rb +1 -1
  225. data/app/forms/hyrax/forms/administrative_set_form.rb +3 -0
  226. data/app/forms/hyrax/forms/batch_edit_form.rb +1 -3
  227. data/app/forms/hyrax/forms/batch_upload_form.rb +14 -0
  228. data/app/forms/hyrax/forms/file_set_edit_form.rb +1 -1
  229. data/app/forms/hyrax/forms/file_set_form.rb +6 -7
  230. data/app/forms/hyrax/forms/pcdm_collection_form.rb +17 -5
  231. data/app/forms/hyrax/forms/pcdm_object_form.rb +11 -3
  232. data/app/forms/hyrax/forms/resource_batch_edit_form.rb +8 -22
  233. data/app/forms/hyrax/forms/resource_form.rb +110 -10
  234. data/app/forms/hyrax/forms.rb +1 -0
  235. data/app/helpers/hyrax/attributes_helper.rb +109 -0
  236. data/app/helpers/hyrax/blacklight_override.rb +26 -0
  237. data/app/helpers/hyrax/collections_helper.rb +2 -0
  238. data/app/helpers/hyrax/file_set_form_helper.rb +24 -0
  239. data/app/helpers/hyrax/hyrax_helper_behavior.rb +51 -2
  240. data/app/helpers/hyrax/iiif_helper.rb +11 -1
  241. data/app/helpers/hyrax/permalink_helper.rb +37 -0
  242. data/app/helpers/hyrax/redirects_tab_helper.rb +29 -0
  243. data/app/helpers/hyrax/work_form_helper.rb +9 -5
  244. data/app/helpers/hyrax/works_helper.rb +14 -0
  245. data/app/indexers/concerns/hyrax/workflow_indexer.rb +30 -0
  246. data/app/indexers/hyrax/file_set_indexer.rb +1 -0
  247. data/app/indexers/hyrax/indexers/administrative_set_indexer.rb +2 -1
  248. data/app/indexers/hyrax/indexers/file_set_indexer.rb +6 -2
  249. data/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb +11 -1
  250. data/app/indexers/hyrax/indexers/pcdm_object_indexer.rb +25 -4
  251. data/app/indexers/hyrax/indexers/redirects_indexer.rb +29 -0
  252. data/app/indexers/hyrax/indexers/resource_indexer.rb +4 -0
  253. data/app/indexers/hyrax/indexers.rb +2 -0
  254. data/app/inputs/controlled_vocabulary_input.rb +7 -1
  255. data/app/jobs/content_deposit_error_event_job.rb +14 -0
  256. data/app/jobs/create_work_job.rb +2 -0
  257. data/app/jobs/migrate_files_to_valkyrie_job.rb +7 -1
  258. data/app/models/batch_upload_item.rb +4 -0
  259. data/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb +10 -0
  260. data/app/models/concerns/hyrax/ability.rb +3 -1
  261. data/app/models/concerns/hyrax/collection_behavior.rb +4 -0
  262. data/app/models/concerns/hyrax/file_set/transcripts.rb +16 -0
  263. data/app/models/concerns/hyrax/file_set_behavior.rb +9 -0
  264. data/app/models/concerns/hyrax/flexibility.rb +107 -0
  265. data/app/models/concerns/hyrax/redirects_normalization.rb +38 -0
  266. data/app/models/concerns/hyrax/solr_document/characterization.rb +1 -1
  267. data/app/models/concerns/hyrax/solr_document/metadata.rb +9 -0
  268. data/app/models/concerns/hyrax/solr_document/ordered_members.rb +4 -0
  269. data/app/models/concerns/hyrax/solr_document_behavior.rb +28 -6
  270. data/app/models/concerns/hyrax/suppressible.rb +1 -1
  271. data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +1 -1
  272. data/app/models/concerns/hyrax/with_embargoes_and_leases.rb +30 -0
  273. data/app/models/concerns/hyrax/work_behavior.rb +8 -0
  274. data/app/models/hyrax/administrative_set.rb +1 -1
  275. data/app/models/hyrax/change_set.rb +3 -1
  276. data/app/models/hyrax/embargo.rb +3 -1
  277. data/app/models/hyrax/file_set.rb +4 -2
  278. data/app/models/hyrax/flexible_schema.rb +219 -0
  279. data/app/models/hyrax/lease.rb +3 -1
  280. data/app/models/hyrax/pcdm_collection.rb +4 -1
  281. data/app/models/hyrax/redirect.rb +64 -0
  282. data/app/models/hyrax/redirect_path.rb +14 -0
  283. data/app/models/hyrax/resource.rb +22 -25
  284. data/app/models/hyrax/riiif/file.rb +43 -0
  285. data/app/models/hyrax/riiif/file_resolver.rb +65 -0
  286. data/app/models/hyrax/uploaded_file.rb +9 -0
  287. data/app/models/hyrax/virus_scanner.rb +16 -3
  288. data/app/models/hyrax/work.rb +4 -1
  289. data/app/models/job_io_wrapper.rb +12 -3
  290. data/app/models/user_mailbox.rb +3 -1
  291. data/app/presenters/hyrax/admin_set_presenter.rb +11 -0
  292. data/app/presenters/hyrax/annotates_content.rb +35 -0
  293. data/app/presenters/hyrax/collection_presenter.rb +5 -1
  294. data/app/presenters/hyrax/displays_content.rb +133 -0
  295. data/app/presenters/hyrax/displays_image.rb +11 -4
  296. data/app/presenters/hyrax/displays_transcripts.rb +59 -0
  297. data/app/presenters/hyrax/file_set_presenter.rb +8 -18
  298. data/app/presenters/hyrax/google_scholar_presenter.rb +39 -0
  299. data/app/presenters/hyrax/iiif_manifest_presenter.rb +22 -4
  300. data/app/presenters/hyrax/missing_method_behavior.rb +15 -0
  301. data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +2 -4
  302. data/app/presenters/hyrax/work_show_presenter.rb +56 -14
  303. data/app/renderers/hyrax/renderers/attribute_renderer.rb +6 -2
  304. data/app/renderers/hyrax/renderers/license_attribute_renderer.rb +10 -10
  305. data/app/renderers/hyrax/renderers/redirects_label_attribute_renderer.rb +25 -0
  306. data/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb +10 -11
  307. data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +1 -5
  308. data/app/search_builders/hyrax/filter_by_type.rb +1 -1
  309. data/app/services/hyrax/action/create_valkyrie_work.rb +3 -2
  310. data/app/services/hyrax/authority_rendering_helper.rb +28 -0
  311. data/app/services/hyrax/authority_service.rb +107 -0
  312. data/app/services/hyrax/callbacks.rb +2 -2
  313. data/app/services/hyrax/collections/nested_collection_query_service.rb +9 -3
  314. data/app/services/hyrax/collections_service.rb +17 -0
  315. data/app/services/hyrax/custom_queries/find_by_property_value.rb +89 -0
  316. data/app/services/hyrax/edit_permissions_service.rb +4 -4
  317. data/app/services/hyrax/file_set_type_service.rb +12 -4
  318. data/app/services/hyrax/flexible_schema_validator_service.rb +153 -0
  319. data/app/services/hyrax/flexible_schema_validators/class_validator.rb +123 -0
  320. data/app/services/hyrax/flexible_schema_validators/core_metadata_validator.rb +211 -0
  321. data/app/services/hyrax/flexible_schema_validators/existing_records_validator.rb +83 -0
  322. data/app/services/hyrax/flexible_schema_validators/redirects_validator.rb +116 -0
  323. data/app/services/hyrax/flexible_schema_validators/schema_validator.rb +34 -0
  324. data/app/services/hyrax/flexible_schema_validators/sort_properties_validator.rb +54 -0
  325. data/app/services/hyrax/license_service.rb +1 -1
  326. data/app/services/hyrax/listeners/metadata_index_listener.rb +11 -0
  327. data/app/services/hyrax/m3_profile_editor.rb +32 -0
  328. data/app/services/hyrax/m3_schema_loader.rb +119 -0
  329. data/app/services/hyrax/manifest_builder_service.rb +18 -24
  330. data/app/services/hyrax/permalink_path.rb +25 -0
  331. data/app/services/hyrax/qa_select_service.rb +9 -5
  332. data/app/services/hyrax/redirect_path_normalizer.rb +58 -0
  333. data/app/services/hyrax/redirects_lookup.rb +59 -0
  334. data/app/services/hyrax/resource_permissions_visibility_propagator.rb +54 -0
  335. data/app/services/hyrax/resource_types_service.rb +3 -20
  336. data/app/services/hyrax/rights_statement_service.rb +1 -1
  337. data/app/services/hyrax/schema_loader.rb +205 -0
  338. data/app/services/hyrax/search_service.rb +1 -1
  339. data/app/services/hyrax/simple_schema_loader.rb +28 -127
  340. data/app/services/hyrax/solr_service.rb +39 -2
  341. data/app/services/hyrax/tolerant_select_service.rb +5 -3
  342. data/app/services/hyrax/valkyrie_upload.rb +2 -2
  343. data/app/services/hyrax/visibility_propagator.rb +4 -1
  344. data/app/services/hyrax/work_uploads_handler.rb +17 -9
  345. data/app/services/hyrax/workflow/workflow_factory.rb +5 -4
  346. data/app/services/migrate_resource_service.rb +7 -1
  347. data/app/uploaders/hyrax/uploaded_file_uploader.rb +2 -2
  348. data/app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb +1 -1
  349. data/app/utils/hyrax/required_data_seeder.rb +1 -0
  350. data/app/utils/hyrax/required_data_seeders/collection_type_seeder.rb +1 -1
  351. data/app/utils/hyrax/required_data_seeders/flexible_profile_seeder.rb +28 -0
  352. data/app/validators/hyrax/controlled_vocabulary_validator.rb +64 -0
  353. data/app/validators/hyrax/redirect_validator.rb +128 -0
  354. data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
  355. data/app/views/collections/edit_fields/_schema_version.html.erb +1 -0
  356. data/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb +24 -2
  357. data/app/views/hyrax/admin/admin_sets/_show_document_list_row.html.erb +1 -1
  358. data/app/views/hyrax/admin/admin_sets/show.html.erb +1 -1
  359. data/app/views/hyrax/admin/analytics/_analytics_error.html.erb +42 -0
  360. data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +11 -9
  361. data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +60 -57
  362. data/app/views/hyrax/admin/features/index.html.erb +1 -1
  363. data/app/views/hyrax/admin/metadata_profiles/_import_modal.html.erb +20 -0
  364. data/app/views/hyrax/admin/metadata_profiles/index.html.erb +54 -0
  365. data/app/views/hyrax/base/_attribute_rows.html.erb +4 -21
  366. data/app/views/hyrax/base/_citations.html.erb +1 -0
  367. data/app/views/hyrax/base/_currently_shared.html.erb +2 -1
  368. data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
  369. data/app/views/hyrax/base/_form_member_of_collections.html.erb +6 -6
  370. data/app/views/hyrax/base/_form_redirects.html.erb +125 -0
  371. data/app/views/hyrax/base/_form_share.html.erb +7 -2
  372. data/app/views/hyrax/base/_member.html.erb +1 -1
  373. data/app/views/hyrax/base/_social_media.html.erb +1 -1
  374. data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
  375. data/app/views/hyrax/base/show.html.erb +3 -0
  376. data/app/views/hyrax/collections/_default_group.html.erb +3 -0
  377. data/app/views/hyrax/collections/_list_collections.html.erb +3 -0
  378. data/app/views/hyrax/collections/_list_works.html.erb +1 -1
  379. data/app/views/hyrax/collections/_show_document_list_row.html.erb +1 -1
  380. data/app/views/hyrax/collections/show.html.erb +4 -0
  381. data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -2
  382. data/app/views/hyrax/dashboard/collections/_button_for_update_collection.html.erb +2 -1
  383. data/app/views/hyrax/dashboard/collections/_default_group.html.erb +3 -0
  384. data/app/views/hyrax/dashboard/collections/_form.html.erb +17 -0
  385. data/app/views/hyrax/dashboard/collections/_form_for_select_collection.html.erb +7 -10
  386. data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +3 -0
  387. data/app/views/hyrax/dashboard/collections/_list_works.html.erb +1 -1
  388. data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
  389. data/app/views/hyrax/dashboard/profiles/_edit_primary.html.erb +1 -8
  390. data/app/views/hyrax/dashboard/profiles/_trophy_edit.html.erb +1 -1
  391. data/app/views/hyrax/dashboard/profiles/show.html.erb +5 -5
  392. data/app/views/hyrax/dashboard/sidebar/_metadata.html.erb +11 -0
  393. data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +1 -0
  394. data/app/views/hyrax/dashboard/works/_default_group.html.erb +3 -0
  395. data/app/views/hyrax/dashboard/works/_list_works.html.erb +4 -2
  396. data/app/views/hyrax/file_sets/_form.html.erb +16 -3
  397. data/app/views/hyrax/file_sets/_metadata.html.erb +35 -0
  398. data/app/views/hyrax/file_sets/_valkyrie_form.html.erb +37 -0
  399. data/app/views/hyrax/file_sets/edit.html.erb +14 -8
  400. data/app/views/hyrax/file_sets/media_display/_audio.html.erb +4 -0
  401. data/app/views/hyrax/file_sets/media_display/_image.html.erb +2 -2
  402. data/app/views/hyrax/file_sets/media_display/_video.html.erb +4 -0
  403. data/app/views/hyrax/homepage/_explore_collections.html.erb +1 -1
  404. data/app/views/hyrax/homepage/_featured_fields.html.erb +1 -1
  405. data/app/views/hyrax/homepage/_recent_document.html.erb +1 -1
  406. data/app/views/hyrax/homepage/robots.text.erb +17 -0
  407. data/app/views/hyrax/my/collections/_default_group.html.erb +3 -0
  408. data/app/views/hyrax/my/collections/_list_collections.html.erb +3 -0
  409. data/app/views/hyrax/my/collections/_modal_add_subcollection.html.erb +2 -2
  410. data/app/views/hyrax/my/collections/_modal_add_to_collection.html.erb +2 -2
  411. data/app/views/hyrax/my/works/_default_group.html.erb +3 -0
  412. data/app/views/hyrax/my/works/_list_works.html.erb +5 -2
  413. data/app/views/hyrax/shared/_copy_permalink.html.erb +10 -0
  414. data/app/views/hyrax/users/_user_info.html.erb +1 -6
  415. data/app/views/layouts/_head_tag_content.html.erb +2 -0
  416. data/app/views/layouts/hyrax/dashboard.html.erb +2 -1
  417. data/app/views/records/edit_fields/_contexts.html.erb +1 -0
  418. data/app/views/records/edit_fields/_license.html.erb +17 -5
  419. data/app/views/records/edit_fields/_resource_type.html.erb +16 -2
  420. data/app/views/records/edit_fields/_rights_statement.html.erb +17 -5
  421. data/app/views/records/edit_fields/_schema_version.html.erb +1 -0
  422. data/app/views/records/edit_fields/_transcript_ids.html.erb +18 -0
  423. data/app/views/records/show_fields/_rights.html.erb +1 -1
  424. data/app/views/shared/_citations.html.erb +46 -31
  425. data/app/views/shared/_schema_version.html.erb +38 -0
  426. data/bin/dev-entrypoint.sh +14 -4
  427. data/chart/hyrax/Chart.yaml +4 -4
  428. data/chart/hyrax/templates/ingress.yaml +3 -0
  429. data/chart/hyrax/values.yaml +10 -8
  430. data/config/features.rb +27 -0
  431. data/config/initializers/blacklight_dynamic_sitemap.rb +43 -0
  432. data/config/initializers/deprecation_patch.rb +27 -0
  433. data/config/initializers/hydra_works.rb +3 -0
  434. data/config/initializers/i18n_extensions.rb +197 -0
  435. data/config/initializers/storage_adapter_initializer.rb +15 -9
  436. data/config/locales/hyrax.de.yml +172 -54
  437. data/config/locales/hyrax.en.yml +183 -66
  438. data/config/locales/hyrax.es.yml +174 -49
  439. data/config/locales/hyrax.fr.yml +169 -45
  440. data/config/locales/hyrax.it.yml +172 -48
  441. data/config/locales/hyrax.pt-BR.yml +172 -54
  442. data/config/locales/hyrax.zh.yml +145 -21
  443. data/config/metadata/basic_metadata.yaml +66 -0
  444. data/config/metadata/batch_edit_metadata.yaml +119 -0
  445. data/config/metadata/file_set_metadata.yaml +19 -0
  446. data/config/metadata/redirects.yaml +15 -0
  447. data/config/metadata_profiles/m3_json_schema.json +487 -0
  448. data/config/metadata_profiles/m3_profile.yaml +954 -0
  449. data/config/routes.rb +9 -0
  450. data/docker-compose-allinson.yml +176 -0
  451. data/docker-compose-dassie.yml +14 -6
  452. data/docker-compose-koppie.yml +18 -10
  453. data/docker-compose-sirenia.yml +20 -10
  454. data/documentation/copy_permalink.md +29 -0
  455. data/documentation/developing-your-hyrax-based-app.md +2 -2
  456. data/documentation/file-ingest-characterization.md +763 -0
  457. data/documentation/flexible_metadata.md +113 -0
  458. data/documentation/forms/field_behaviors.md +297 -0
  459. data/documentation/redirects.md +428 -0
  460. data/hyrax.gemspec +7 -2
  461. data/lib/freyja/metadata_adapter.rb +1 -1
  462. data/lib/freyja/persister.rb +25 -1
  463. data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +2 -2
  464. data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +5 -1
  465. data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +5 -1
  466. data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +6 -1
  467. data/lib/generators/hyrax/iiif_viewer/USAGE +22 -0
  468. data/lib/generators/hyrax/iiif_viewer/iiif_viewer_generator.rb +49 -0
  469. data/lib/generators/hyrax/iiif_viewer/templates/_clover.html.erb +7 -0
  470. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.css +3328 -0
  471. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.html +16 -0
  472. data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.js +237 -0
  473. data/lib/generators/hyrax/install_generator.rb +25 -1
  474. data/lib/generators/hyrax/riiif_generator.rb +1 -1
  475. data/lib/generators/hyrax/templates/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
  476. data/lib/generators/hyrax/templates/config/clamav.rb +2 -0
  477. data/lib/generators/hyrax/templates/config/initializers/riiif.rb +4 -80
  478. data/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb +9 -0
  479. data/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb +5 -0
  480. data/lib/generators/hyrax/templates/db/migrate/20260430000001_create_hyrax_redirect_paths.rb.erb +22 -0
  481. data/lib/generators/hyrax/templates/db/migrate/20260521003627_add_additional_redirect_info.rb.erb +39 -0
  482. data/lib/generators/hyrax/templates/package.json +1 -1
  483. data/lib/generators/hyrax/templates/uv.html +60 -82
  484. data/lib/generators/hyrax/work/templates/indexer.rb.erb +1 -1
  485. data/lib/generators/hyrax/work/templates/model.rb.erb +5 -1
  486. data/lib/generators/hyrax/work_resource/templates/form.rb.erb +5 -2
  487. data/lib/generators/hyrax/work_resource/templates/indexer.rb.erb +6 -2
  488. data/lib/generators/hyrax/work_resource/templates/work.rb.erb +5 -2
  489. data/lib/generators/hyrax/work_resource/work_resource_generator.rb +1 -0
  490. data/lib/hyrax/active_fedora_dummy_model.rb +6 -0
  491. data/lib/hyrax/configuration.rb +197 -3
  492. data/lib/hyrax/deprecation.rb +31 -0
  493. data/lib/hyrax/engine.rb +2 -0
  494. data/lib/hyrax/form_fields.rb +17 -5
  495. data/lib/hyrax/indexer.rb +31 -2
  496. data/lib/hyrax/resource_sync/resource_list_writer.rb +3 -0
  497. data/lib/hyrax/schema.rb +15 -4
  498. data/lib/hyrax/specs/shared_specs/factories/administrative_sets.rb +12 -0
  499. data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +1 -1
  500. data/lib/hyrax/specs/shared_specs/factories/hyrax_file_set.rb +13 -0
  501. data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +5 -1
  502. data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +14 -0
  503. data/lib/hyrax/specs/shared_specs/simple_work.rb +41 -0
  504. data/lib/hyrax/specs/shared_specs.rb +1 -0
  505. data/lib/hyrax/transactions/collection_create.rb +2 -1
  506. data/lib/hyrax/transactions/collection_destroy.rb +1 -0
  507. data/lib/hyrax/transactions/collection_update.rb +2 -1
  508. data/lib/hyrax/transactions/container.rb +28 -0
  509. data/lib/hyrax/transactions/steps/apply_permission_template_on_update.rb +65 -0
  510. data/lib/hyrax/transactions/steps/apply_workflow_on_admin_set_change.rb +97 -0
  511. data/lib/hyrax/transactions/steps/ensure_admin_set.rb +1 -1
  512. data/lib/hyrax/transactions/steps/remove_redirect_paths.rb +35 -0
  513. data/lib/hyrax/transactions/steps/save.rb +10 -0
  514. data/lib/hyrax/transactions/steps/set_default_admin_set.rb +1 -1
  515. data/lib/hyrax/transactions/steps/sync_redirect_paths.rb +141 -0
  516. data/lib/hyrax/transactions/work_create.rb +2 -1
  517. data/lib/hyrax/transactions/work_destroy.rb +1 -0
  518. data/lib/hyrax/transactions/work_update.rb +4 -1
  519. data/lib/hyrax/version.rb +1 -1
  520. data/lib/hyrax.rb +61 -0
  521. data/lib/tasks/m3_profile_cleanup.rake +35 -0
  522. data/template.rb +4 -1
  523. metadata +313 -19
  524. data/.dassie/public/robots.txt +0 -1
  525. data/.koppie/public/robots.txt +0 -1
  526. data/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb +0 -39
  527. data/app/views/catalog/_thumbnail_list_collection.html.erb +0 -4
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ # Form-side handling for the `based_near` (location) controlled vocabulary
4
+ # field. The form expects a `ControlledVocabularies::Location` object as
5
+ # input and produces a hash like those used with `accepts_nested_attributes_for`.
6
+ #
7
+ # The `deserialize!` override below is the canonical Field Behavior pattern
8
+ # for nested-attribute properties: a module prepended onto every
9
+ # `ResourceForm` subclass that strips its own key from the rewritten params
10
+ # so Reform's `from_hash` doesn't write the raw `_attributes` payload to a
11
+ # same-named property. Calling `super` first lets the chain compose — every
12
+ # Field Behavior runs its own delete, then control falls through to Reform's
13
+ # base `deserialize!` (the `<name>_attributes` rename pass).
14
+ module BasedNearFieldBehavior
15
+ def self.included(descendant)
16
+ descendant.property :based_near_attributes, virtual: true, populator: :based_near_attributes_populator, prepopulator: :based_near_attributes_prepopulator
17
+ end
18
+
19
+ # Skipping based_near in deserialize avoids a race condition where it
20
+ # would otherwise end up in an inconsistent state during validation; the
21
+ # field is handled exclusively by the populator on
22
+ # `based_near_attributes`.
23
+ #
24
+ # Override `deserialize!` (not `deserialize`) so the strip runs *after*
25
+ # Reform's `FormBuilderMethods#deserialize!` has renamed
26
+ # `based_near_attributes` to `based_near`, but *before* `from_hash`
27
+ # reads property values from the params. Stripping in `deserialize`
28
+ # would happen before the rename, and the rename would put the key
29
+ # back; `from_hash` would then write raw fragment hashes onto the
30
+ # form's `based_near` field, breaking the populator's contract.
31
+ #
32
+ # Mutate `params` in place — never replace it. Reform's `validate(params)`
33
+ # exposes the same hash via `form.input_params`, and downstream callers
34
+ # (`WorksControllerBehavior#update_valkyrie_work` reading
35
+ # `form.input_params["permissions"]`) read from that exact reference
36
+ # *after* the rename.
37
+ def deserialize!(params)
38
+ result = super
39
+ if result.respond_to?(:delete)
40
+ result.delete('based_near')
41
+ result.delete(:based_near)
42
+ end
43
+ result
44
+ end
45
+
46
+ private
47
+
48
+ def based_near_attributes_populator(fragment:, **_options)
49
+ return unless respond_to?(:based_near)
50
+ adds = []
51
+ deletes = []
52
+ fragment.each do |_, h|
53
+ uri = RDF::URI.parse(h["id"]).to_s
54
+ if h["_destroy"] == "true"
55
+ deletes << uri
56
+ else
57
+ adds << uri
58
+ end
59
+ end
60
+ self.based_near = ((model.based_near + adds) - deletes).uniq
61
+ end
62
+
63
+ def based_near_attributes_prepopulator
64
+ return unless respond_to?(:based_near)
65
+ self.based_near = based_near&.map do |loc|
66
+ uri = RDF::URI.parse(loc)
67
+ if uri
68
+ Hyrax::ControlledVocabularies::Location.new(uri)
69
+ else
70
+ loc
71
+ end
72
+ end
73
+ self.based_near ||= []
74
+ self.based_near << Hyrax::ControlledVocabularies::Location.new if self.based_near.blank?
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module FlexibleFormBehavior
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ property :contexts
8
+
9
+ validate :validate_flexible_required_fields
10
+ end
11
+
12
+ def validate_flexible_required_fields
13
+ required_fields = singleton_class.schema_definitions.select { |_, opts| opts[:required] }.keys
14
+
15
+ required_fields.each do |field|
16
+ value = send(field)
17
+ errors.add(field, :blank) if value.blank?
18
+ end
19
+ end
20
+
21
+ # OVERRIDE disposable 0.6.3 to make schema dynamic
22
+ def schema
23
+ Hyrax::Forms::ResourceForm::Definition::Each.new(singleton_class.schema_definitions)
24
+ end
25
+
26
+ private
27
+
28
+ # OVERRIDE valkyrie 3.0.1 to make schema dynamic
29
+ def field(field_name)
30
+ singleton_class.schema_definitions.fetch(field_name.to_s)
31
+ end
32
+
33
+ def _form_field_definitions
34
+ singleton_class.schema_definitions
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyrax
4
+ # Form-side handling for the `redirects` nested-attribute field.
5
+ #
6
+ # Submitted form payloads arrive under `redirects_attributes` and are
7
+ # turned into plain hashes (the persisted shape — see
8
+ # `config/metadata/redirects.yaml`, `type: hash`) by the populator.
9
+ # The form partial wraps each persisted hash in a `Hyrax::Redirect`
10
+ # value object at render time so the view can call `.path` and
11
+ # `.is_display_url`.
12
+ #
13
+ # The `deserialize!` override removes the renamed `redirects` key
14
+ # before Reform's `from_hash` runs, so the form's `redirects`
15
+ # property is written exclusively by the populator. See
16
+ # `Hyrax::BasedNearFieldBehavior` for the parallel pattern.
17
+ #
18
+ # ## Feature gating
19
+ #
20
+ # `self.included` runs at class load time and uses the structural
21
+ # gate `Hyrax.config.redirects_enabled?`. The runtime Flipflop
22
+ # check isn't meaningful here because the form class is being
23
+ # defined, not handling a request.
24
+ #
25
+ # All runtime-side methods (`deserialize!`, populator) delegate to
26
+ # `Hyrax.config.redirects_active?`, the two-gate combinator
27
+ # (`redirects_enabled? && Flipflop.redirects?`). Calling
28
+ # `Flipflop.redirects?` directly is unsafe when the config is off
29
+ # because the feature isn't registered in that case.
30
+ module RedirectsFieldBehavior
31
+ def self.included(descendant)
32
+ return unless Hyrax.config.redirects_enabled?
33
+ # Declare the radio-group scalar before redirects_attributes so Reform
34
+ # deserializes it first; the populator reads its value while building
35
+ # per-row entries.
36
+ descendant.property :redirects_display_url_index, virtual: true
37
+ descendant.property :redirects_attributes,
38
+ virtual: true,
39
+ populator: :redirects_attributes_populator
40
+ end
41
+
42
+ # Reform's FormBuilderMethods rewrites `redirects_attributes` →
43
+ # `redirects` before `from_hash` runs. Strip the renamed key so
44
+ # the populator on `redirects_attributes` is the single entry
45
+ # point for form-driven writes.
46
+ def deserialize!(params)
47
+ result = super
48
+ if Hyrax.config.redirects_active? && result.respond_to?(:delete)
49
+ result.delete('redirects')
50
+ result.delete(:redirects)
51
+ end
52
+ result
53
+ end
54
+
55
+ private
56
+
57
+ # Builds plain hashes (the persisted shape) from the submitted
58
+ # `redirects_attributes` payload. Drops rows marked for destruction
59
+ # or with a blank path. Normalizes paths up-front so the validator
60
+ # sees normalized form (so DSpace-style pasted URLs validate cleanly).
61
+ #
62
+ # When `redirects_display_url_index` is set (form-driven radio
63
+ # group), the matching original-index row gets `is_display_url: true`
64
+ # and all other rows get false. When absent (Bulkrax import path),
65
+ # the row's own `is_display_url` value is honored.
66
+ def redirects_attributes_populator(fragment:, **_options)
67
+ return unless respond_to?(:redirects)
68
+ return unless Hyrax.config.redirects_active?
69
+ pairs = redirects_fragment_pairs(fragment)
70
+ self.redirects = pairs.sort_by { |k, _row| k.to_i }
71
+ .map { |k, row| redirects_entry_from(k, row) }
72
+ .compact
73
+ end
74
+
75
+ def redirects_fragment_pairs(fragment)
76
+ return {} if fragment.nil?
77
+ fragment.respond_to?(:to_unsafe_h) ? fragment.to_unsafe_h : fragment.to_h
78
+ end
79
+
80
+ def redirects_entry_from(key, row)
81
+ row = row.respond_to?(:to_unsafe_h) ? row.to_unsafe_h : row
82
+ return nil if row['_destroy'].to_s == 'true' || row['path'].to_s.strip.empty?
83
+ { 'path' => Hyrax::RedirectPathNormalizer.call(row['path']),
84
+ 'is_display_url' => redirects_is_display_url_flag_for(key, row) }
85
+ end
86
+
87
+ def redirects_is_display_url_flag_for(key, row)
88
+ if redirects_display_url_index.nil?
89
+ row['is_display_url'].to_s == 'true'
90
+ else
91
+ key.to_s == redirects_display_url_index.to_s
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ module Hyrax
3
+ module TranscriptsBehavior
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ def available_transcripts(parent:, current_ability:)
8
+ member_ids = Hyrax.custom_queries.find_child_file_set_ids(resource: parent)
9
+ Hyrax::SolrQueryService.new
10
+ # Cast Valkyrie::IDs to strings
11
+ .with_ids(ids: member_ids.map(&:to_s).to_a)
12
+ .accessible_by(ability: current_ability, action: :edit)
13
+ .solr_documents(
14
+ # Using "has_model_ssim:*FileSet" in fq will return both FileSet
15
+ # and Hyrax::FileSet documents. In test mode, Koppie and Sirenia
16
+ # index file sets with has_model_ssim:Hyrax::FileSet.
17
+ # But in dev mode, they index file sets with
18
+ # has_model_ssim:FileSet instead. This query covers both cases.
19
+ fq: [mime_type_filter_query.to_s, "has_model_ssim:*FileSet"],
20
+ fl: "id,title_tesim",
21
+ rows: 1000
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def mime_type_filter_query
28
+ valid_mime_types.map { |type| "mime_type_ssi:\"#{type}\"" }.join(" OR ")
29
+ end
30
+
31
+ # According to IIIF, .srt and .ttml are also acceptable but may
32
+ # not be supported by viewers. Clover and Ramp are confirmed to work
33
+ # with .vtt. (https://iiif.io/api/cookbook/recipe/0219-using-caption-file/).
34
+ # When Hyrax supports Ramp, we may want to add "text/plain" (.srt) to this list.
35
+ def valid_mime_types
36
+ ["text/vtt"]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -8,7 +8,7 @@ module Hyrax
8
8
  # Cast any array values on the model to scalars.
9
9
  def [](key)
10
10
  return super if key == :thumbnail_id
11
- super.first
11
+ super&.first
12
12
  end
13
13
 
14
14
  def permission_template
@@ -6,6 +6,8 @@ module Hyrax
6
6
  # @api public
7
7
  # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking
8
8
  class AdministrativeSetForm < Hyrax::Forms::ResourceForm
9
+ check_if_flexible(Hyrax::AdministrativeSet)
10
+
9
11
  ##
10
12
  # @api private
11
13
  AdminSetMembersPopulator = lambda do |**_options|
@@ -22,6 +24,7 @@ module Hyrax
22
24
 
23
25
  property :title, required: true, primary: true
24
26
  property :description, primary: true
27
+ property :contexts, primary: true if Hyrax.config.admin_set_flexible?
25
28
 
26
29
  property :creator
27
30
 
@@ -5,8 +5,7 @@ module Hyrax
5
5
  # Used for drawing the fields that appear on the page
6
6
  self.terms = [:creator, :contributor, :description,
7
7
  :keyword, :resource_type, :license, :publisher, :date_created,
8
- :subject, :language, :identifier, :based_near,
9
- :related_url]
8
+ :subject, :language, :identifier, :related_url]
10
9
  self.required_fields = []
11
10
  self.model_class = Hyrax.primary_work_type
12
11
 
@@ -39,7 +38,6 @@ module Hyrax
39
38
  { subject: [] },
40
39
  { language: [] },
41
40
  { identifier: [] },
42
- { based_near: [] },
43
41
  { related_url: [] },
44
42
  { permissions_attributes: [:type, :name, :access, :id, :_destroy] },
45
43
  :on_behalf_of,
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
3
+ # It isn't ideal but this form is used for both active fedora and valkyrie.
2
4
  module Hyrax
3
5
  module Forms
4
6
  class BatchUploadForm < Hyrax::Forms::WorkForm
@@ -22,6 +24,18 @@ module Hyrax
22
24
  super - [:title]
23
25
  end
24
26
 
27
+ def required_fields
28
+ return super unless Hyrax.config.use_valkyrie?
29
+ form_class.required_fields
30
+ end
31
+
32
+ def payload_class
33
+ @payload_class ||= Valkyrie.config.resource_class_resolver.call(payload_concern)
34
+ end
35
+
36
+ def form_class
37
+ @form_class ||= "#{payload_class}Form".safe_constantize
38
+ end
25
39
  # # On the batch upload, title is set per-file.
26
40
  # def secondary_terms
27
41
  # super - [:title]
@@ -12,7 +12,7 @@ module Hyrax::Forms
12
12
 
13
13
  self.terms = [:resource_type, :title, :creator, :contributor, :description,
14
14
  :keyword, :license, :publisher, :date_created, :subject, :language,
15
- :identifier, :based_near, :related_url,
15
+ :identifier, :based_near, :related_url, :transcript_ids,
16
16
  :visibility_during_embargo, :visibility_after_embargo, :embargo_release_date,
17
17
  :visibility_during_lease, :visibility_after_lease, :lease_expiration_date,
18
18
  :visibility]
@@ -5,17 +5,16 @@ module Hyrax
5
5
  ##
6
6
  # A form for +Hyrax::FileSet+s.
7
7
  class FileSetForm < Hyrax::Forms::ResourceForm
8
- include Hyrax::FormFields(:core_metadata)
9
-
10
- # The fields in +:file_set_metadata+ were hardcoded into this form in a
11
- # previous version of Hyrax, but ideally in the future this metadata will
12
- # be configurable.
13
- include Hyrax::FormFields(:file_set_metadata)
14
-
8
+ if Hyrax.config.file_set_include_metadata?
9
+ include Hyrax::FormFields(:core_metadata)
10
+ include Hyrax::FormFields(:file_set_metadata)
11
+ end
12
+ check_if_flexible(Hyrax::FileSet)
15
13
  include Hyrax::DepositAgreementBehavior
16
14
  include Hyrax::ContainedInWorksBehavior
17
15
  include Hyrax::LeaseabilityBehavior
18
16
  include Hyrax::PermissionBehavior
17
+ include Hyrax::TranscriptsBehavior
19
18
 
20
19
  property :representative_id, type: Valkyrie::Types::String, writeable: false
21
20
  property :thumbnail_id, type: Valkyrie::Types::String, writeable: false
@@ -6,7 +6,16 @@ module Hyrax
6
6
  # @api public
7
7
  # @see https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking
8
8
  class PcdmCollectionForm < Hyrax::Forms::ResourceForm # rubocop:disable Metrics/ClassLength
9
- include Hyrax::FormFields(:core_metadata)
9
+ include Hyrax::FormFields(:core_metadata) if Hyrax.config.collection_include_metadata?
10
+ include RedirectsFieldBehavior
11
+ include Hyrax::FormFields(:redirects) if Hyrax.config.redirects_enabled? && Hyrax.config.collection_include_metadata?
12
+ if Hyrax.config.redirects_enabled?
13
+ validation(name: :default, inherit: true) do
14
+ validates_with Hyrax::RedirectValidator, attributes: [:redirects]
15
+ end
16
+ end
17
+
18
+ check_if_flexible(Hyrax::PcdmCollection)
10
19
 
11
20
  BannerInfoPrepopulator = lambda do |**_options|
12
21
  self.banner_info ||= begin
@@ -33,7 +42,7 @@ module Hyrax
33
42
  end
34
43
  end
35
44
 
36
- property :depositor, required: true
45
+ property :depositor
37
46
  property :collection_type_gid, required: true
38
47
  property :visibility, default: VisibilityIntention::PRIVATE
39
48
 
@@ -62,9 +71,12 @@ module Hyrax
62
71
  # @return [Array<Symbol>] terms for display 'above-the-fold', or in the most
63
72
  # prominent form real estate
64
73
  def primary_terms
65
- _form_field_definitions
66
- .select { |_, definition| definition[:primary] }
67
- .keys.map(&:to_sym)
74
+ terms = _form_field_definitions
75
+ .select { |_, definition| definition[:primary] }
76
+ .keys.map(&:to_sym)
77
+
78
+ terms = [:schema_version] + terms if model.flexible?
79
+ terms
68
80
  end
69
81
 
70
82
  ##
@@ -9,13 +9,21 @@ module Hyrax
9
9
  # Although File Sets are technically also PCDM objects, they use a separate
10
10
  # form class: +Hyrax::Forms::FileSetForm+.
11
11
  class PcdmObjectForm < Hyrax::Forms::ResourceForm
12
- include Hyrax::FormFields(:core_metadata)
13
-
14
12
  include Hyrax::ContainedInWorksBehavior
15
13
  include Hyrax::DepositAgreementBehavior
16
14
  include Hyrax::LeaseabilityBehavior
17
15
  include Hyrax::PermissionBehavior
18
16
 
17
+ # redirects is wired here (and on PcdmCollectionForm), not on the shared
18
+ # ResourceForm; see ResourceForm for why FileSetForm must not inherit it.
19
+ include RedirectsFieldBehavior
20
+ include Hyrax::FormFields(:redirects) if Hyrax.config.redirects_enabled? && Hyrax.config.work_include_metadata?
21
+ if Hyrax.config.redirects_enabled?
22
+ validation(name: :default, inherit: true) do
23
+ validates_with Hyrax::RedirectValidator, attributes: [:redirects]
24
+ end
25
+ end
26
+
19
27
  property :on_behalf_of
20
28
  property :proxy_depositor
21
29
 
@@ -37,7 +45,7 @@ module Hyrax
37
45
  private
38
46
 
39
47
  def admin_set_prepopulator
40
- self.admin_set_id ||= Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id.to_s
48
+ self.admin_set_id = Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id.to_s if admin_set_id.to_s.blank?
41
49
  end
42
50
 
43
51
  def in_collections_populator(fragment:, **_options)
@@ -2,19 +2,20 @@
2
2
  module Hyrax
3
3
  module Forms
4
4
  class ResourceBatchEditForm < Hyrax::Forms::ResourceForm
5
- include Hyrax::FormFields(:basic_metadata)
5
+ # batch edit is unfortunately all or nothing when it comes to flexible metadata
6
+ # because the form could be a mix of AF records, Valkyrie records and Flexible Valkyrie records
7
+ # we have no real way of turning this on or off more precisely
8
+ include Hyrax::FormFields(:batch_edit_metadata) unless Hyrax.primary_work_type.flexible?
6
9
 
7
10
  include Hyrax::ContainedInWorksBehavior
8
11
  include Hyrax::DepositAgreementBehavior
9
12
  include Hyrax::LeaseabilityBehavior
10
13
  include Hyrax::PermissionBehavior
11
14
 
15
+ class_attribute :terms
12
16
  self.required_fields = []
13
- self.model_class = Hyrax.primary_work_type
14
-
15
- # Terms that need to exclude from batch edit
16
- class_attribute :terms_excluded
17
- self.terms_excluded = [:abstract, :label, :source]
17
+ self.model_class = Valkyrie.config.resource_class_resolver.call(Hyrax.primary_work_type.to_s)
18
+ self.terms = Hyrax::Forms::BatchEditForm.terms
18
19
 
19
20
  # Contains a list of titles of all the works in the batch
20
21
  attr_accessor :names
@@ -33,21 +34,6 @@ module Hyrax
33
34
  end
34
35
  end
35
36
 
36
- def terms
37
- self.class.terms
38
- end
39
-
40
- def self.terms
41
- return Hyrax::Forms::BatchEditForm.terms if model_class < ActiveFedora::Base
42
-
43
- terms_primary = definitions.select { |_, definition| definition[:primary] }
44
- .keys.map(&:to_sym)
45
- terms_secondary = definitions.select { |_, definition| definition[:display] && !definition[:primary] }
46
- .keys.map(&:to_sym)
47
-
48
- (terms_primary + terms_secondary) - terms_excluded
49
- end
50
-
51
37
  attr_reader :batch_document_ids
52
38
 
53
39
  # Returns a list of parameters we accept from the form
@@ -101,7 +87,7 @@ module Hyrax
101
87
  # For each of the files in the batch, set the attributes to be the concatenation of all the attributes
102
88
  batch_document_ids.each_with_object({}) do |doc_id, combined_attributes|
103
89
  work = Hyrax.query_service.find_by(id: doc_id)
104
- terms.each do |field|
90
+ self.class.terms.each do |field|
105
91
  combined_attributes[field] ||= []
106
92
  combined_attributes[field] = (combined_attributes[field] + Array.wrap(work[field])).uniq
107
93
  end