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.
- checksums.yaml +4 -4
- data/.dassie/.env +5 -1
- data/.dassie/Gemfile +4 -2
- data/.dassie/app/assets/images/bulkrax/removed.png +0 -0
- data/.dassie/app/assets/javascripts/application.js +2 -0
- data/.dassie/app/assets/stylesheets/application.css +1 -0
- data/.dassie/app/controllers/catalog_controller.rb +1 -0
- data/.dassie/app/forms/admin_set_resource_form.rb +6 -0
- data/.dassie/app/forms/collection_resource_form.rb +5 -2
- data/.dassie/app/forms/generic_work_resource_form.rb +5 -2
- data/.dassie/app/forms/monograph_form.rb +5 -3
- data/.dassie/app/indexers/admin_set_resource_indexer.rb +5 -0
- data/.dassie/app/indexers/collection_resource_indexer.rb +3 -3
- data/.dassie/app/indexers/generic_work_resource_indexer.rb +6 -3
- data/.dassie/app/indexers/monograph_indexer.rb +6 -2
- data/.dassie/app/models/ability.rb +8 -0
- data/.dassie/app/models/collection_resource.rb +4 -2
- data/.dassie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
- data/.dassie/app/models/generic_work_resource.rb +5 -2
- data/.dassie/app/models/monograph.rb +5 -2
- data/.dassie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
- data/.dassie/bin/importer +142 -0
- data/.dassie/bin/web +4 -0
- data/.dassie/config/browse_everything_providers.yml +1 -1
- data/.dassie/config/bulkrax_api.yml +86 -0
- data/.dassie/config/initializers/bulkrax.rb +92 -0
- data/.dassie/config/initializers/clamav.rb +2 -0
- data/.dassie/config/initializers/hyrax.rb +7 -1
- data/.dassie/config/initializers/riiif.rb +4 -80
- data/.dassie/config/initializers/wings.rb +1 -1
- data/.dassie/config/metadata_profiles/m3_profile.yaml +929 -0
- data/.dassie/config/puma.rb +4 -2
- data/.dassie/config/routes.rb +7 -0
- data/.dassie/config/sidekiq.yml +17 -0
- data/.dassie/config/uv/uv.html +63 -81
- data/.dassie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
- data/.dassie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
- data/.dassie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
- data/.dassie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
- data/.dassie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
- data/.dassie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
- data/.dassie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
- data/.dassie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
- data/.dassie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
- data/.dassie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
- data/.dassie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
- data/.dassie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
- data/.dassie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
- data/.dassie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
- data/.dassie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
- data/.dassie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
- data/.dassie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
- data/.dassie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
- data/.dassie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
- data/.dassie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.dassie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
- data/.dassie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
- data/.dassie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
- data/.dassie/db/schema.rb +154 -1
- data/.dassie/package.json +1 -1
- data/.dassie/rspec_split_configuration.json +835 -0
- data/.dassie/solr/conf/solrconfig.xml +21 -5
- data/.github/{ISSUE_TEMPLATE.md → ISSUE_TEMPLATE/issue_template.md} +5 -0
- data/.github/workflows/lint-build-test.yml +5 -1
- data/.github/workflows/release-charts.yml +48 -0
- data/.gitignore +6 -0
- data/.koppie/.env +5 -1
- data/.koppie/Gemfile +3 -1
- data/.koppie/app/assets/images/bulkrax/removed.png +0 -0
- data/.koppie/app/assets/javascripts/application.js +2 -0
- data/.koppie/app/assets/stylesheets/application.css +1 -0
- data/.koppie/app/controllers/catalog_controller.rb +1 -1
- data/.koppie/app/forms/collection_resource_form.rb +5 -2
- data/.koppie/app/forms/file_set_form.rb +5 -0
- data/.koppie/app/forms/generic_work_form.rb +5 -3
- data/.koppie/app/forms/monograph_form.rb +5 -3
- data/.koppie/app/indexers/collection_resource_indexer.rb +5 -2
- data/.koppie/app/indexers/file_set_indexer.rb +7 -0
- data/.koppie/app/indexers/generic_work_indexer.rb +6 -3
- data/.koppie/app/indexers/monograph_indexer.rb +6 -2
- data/.koppie/app/models/ability.rb +8 -0
- data/.koppie/app/models/collection_resource.rb +4 -2
- data/.koppie/app/models/concerns/bulkrax/has_local_processing.rb +8 -0
- data/.koppie/app/models/generic_work.rb +5 -2
- data/.koppie/app/models/monograph.rb +5 -2
- data/.koppie/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
- data/.koppie/bin/importer +142 -0
- data/.koppie/bin/web +4 -0
- data/.koppie/config/browse_everything_providers.yml +2 -0
- data/.koppie/config/bulkrax_api.yml +86 -0
- data/.koppie/config/initializers/bulkrax.rb +92 -0
- data/.koppie/config/initializers/clamav.rb +2 -0
- data/.koppie/config/initializers/hyrax.rb +11 -3
- data/.koppie/config/initializers/riiif.rb +4 -82
- data/.koppie/config/metadata_profiles/m3_profile.yaml +930 -0
- data/.koppie/config/routes.rb +7 -0
- data/.koppie/config/sidekiq.yml +2 -0
- data/.koppie/config/uv/uv.html +63 -81
- data/.koppie/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb +9 -0
- data/.koppie/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb +5 -0
- data/.koppie/db/migrate/20250826142438_create_bulkrax_importers.bulkrax.rb +19 -0
- data/.koppie/db/migrate/20250826142439_create_bulkrax_importer_runs.bulkrax.rb +17 -0
- data/.koppie/db/migrate/20250826142440_create_bulkrax_entries.bulkrax.rb +17 -0
- data/.koppie/db/migrate/20250826142441_add_status_to_entry.bulkrax.rb +10 -0
- data/.koppie/db/migrate/20250826142442_add_collections_to_importer_runs.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142443_change_collection_ids_on_entries.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142444_create_bulkrax_exporters.bulkrax.rb +20 -0
- data/.koppie/db/migrate/20250826142445_create_bulkrax_exporter_runs.bulkrax.rb +15 -0
- data/.koppie/db/migrate/20250826142446_change_importer_and_exporter_to_polymorphic.bulkrax.rb +19 -0
- data/.koppie/db/migrate/20250826142447_add_total_collection_records_to_importer_runs.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142448_add_children_to_importer_runs.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142449_change_total_records_to_total_work_entries.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142450_change_entry_last_error.bulkrax.rb +20 -0
- data/.koppie/db/migrate/20250826142451_add_validate_only_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142452_add_status_to_importers.bulkrax.rb +10 -0
- data/.koppie/db/migrate/20250826142453_remove_foreign_key_from_bulkrax_entries.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142454_add_status_to_exporters.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142455_add_invalid_record_to_importer_run.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142456_create_bulkrax_statuses.bulkrax.rb +19 -0
- data/.koppie/db/migrate/20250826142457_move_to_statuses.bulkrax.rb +31 -0
- data/.koppie/db/migrate/20250826142458_add_date_filter_and_status_to_bulkrax_exporters.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142459_add_workflow_status_to_bulkrax_exporter.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142460_remove_unused_last_error.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142461_increase_text_sizes.bulkrax.rb +13 -0
- data/.koppie/db/migrate/20250826142462_change_bulkrax_statuses_error_message_column_type_to_text.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142463_rename_children_counters_to_relationships.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142464_add_file_set_counters_to_importer_runs.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142465_add_import_attempts_to_entries.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142466_add_work_counters_to_importer_runs.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142467_create_bulkrax_pending_relationships.bulkrax.rb +14 -0
- data/.koppie/db/migrate/20250826142468_add_order_to_bulkrax_pending_relationships.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142469_add_include_thumbnails_to_bulkrax_exporters.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142470_add_generated_metadata_to_bulkrax_exporters.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142471_rename_bulkrax_importer_run_to_importer_run.bulkrax.rb +18 -0
- data/.koppie/db/migrate/20250826142472_add_indices_to_bulkrax.bulkrax.rb +26 -0
- data/.koppie/db/migrate/20250826142473_denormalize_status_message.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142474_update_identifier_index.bulkrax.rb +7 -0
- data/.koppie/db/migrate/20250826142475_add_index_to_metadata_bulkrax_identifier.bulkrax.rb +19 -0
- data/.koppie/db/migrate/20250826142476_add_file_name_to_uploaded_files.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142477_add_error_tracking_to_pending_relationships.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142478_add_last_imported_at_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142479_add_next_import_at_to_bulkrax_importers.bulkrax.rb +6 -0
- data/.koppie/db/migrate/20250826142480_entry_error_denormalization.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20250826142481_faster_first_entry.bulkrax.rb +8 -0
- data/.koppie/db/migrate/20260430000001_create_hyrax_redirect_paths.hyrax.rb +13 -0
- data/.koppie/db/migrate/20260521003627_add_additional_redirect_info.hyrax.rb +32 -0
- data/.koppie/db/schema.rb +154 -1
- data/.koppie/package.json +1 -1
- data/.koppie/rspec_split_configuration.json +835 -0
- data/.koppie/solr/conf/solrconfig.xml +0 -5
- data/.koppie/yarn.lock +5587 -752
- data/.rubocop.yml +1 -0
- data/CONTAINERS.md +2 -0
- data/Dockerfile +9 -22
- data/Gemfile +0 -1
- data/Gemfile.allinson +2 -0
- data/README.md +1 -2
- data/app/actors/hyrax/actors/file_actor.rb +2 -0
- data/app/actors/hyrax/actors/file_set_actor.rb +1 -1
- data/app/assets/javascripts/hyrax/app.js.erb +143 -10
- data/app/assets/javascripts/hyrax/collection_select.js +68 -0
- data/app/assets/javascripts/hyrax/copy_permalink_button.js +28 -0
- data/app/assets/javascripts/hyrax/redirects.js +45 -0
- data/app/assets/javascripts/hyrax/relationships/control.es6 +21 -1
- data/app/assets/javascripts/hyrax/select_work_type.es6 +7 -2
- data/app/assets/javascripts/hyrax.js +3 -1
- data/app/assets/stylesheets/hyrax/_file-show.scss +1 -0
- data/app/assets/stylesheets/hyrax/_viewer.scss +8 -0
- data/app/assets/stylesheets/hyrax/dashboard.scss +22 -1
- data/app/assets/stylesheets/hyrax/sidebar.scss +98 -3
- data/app/authorities/qa/authorities/collections.rb +9 -9
- data/app/controllers/concerns/hyrax/analytics_error_handling.rb +97 -0
- data/app/controllers/concerns/hyrax/collections_controller_behavior.rb +3 -1
- data/app/controllers/concerns/hyrax/ensure_migrated_behavior.rb +50 -0
- data/app/controllers/concerns/hyrax/flexible_catalog_behavior.rb +206 -0
- data/app/controllers/concerns/hyrax/flexible_schema_behavior.rb +17 -0
- data/app/controllers/concerns/hyrax/redirect_to_display_url.rb +54 -0
- data/app/controllers/concerns/hyrax/works_controller_behavior.rb +52 -10
- data/app/controllers/hyrax/admin/admin_sets_controller.rb +21 -13
- data/app/controllers/hyrax/admin/analytics/collection_reports_controller.rb +2 -0
- data/app/controllers/hyrax/admin/analytics/work_reports_controller.rb +1 -0
- data/app/controllers/hyrax/admin/metadata_profiles_controller.rb +66 -0
- data/app/controllers/hyrax/batch_uploads_controller.rb +2 -0
- data/app/controllers/hyrax/dashboard/collections_controller.rb +27 -6
- data/app/controllers/hyrax/dashboard/nest_collections_controller.rb +2 -1
- data/app/controllers/hyrax/dashboard_controller.rb +2 -1
- data/app/controllers/hyrax/file_sets_controller.rb +19 -1
- data/app/controllers/hyrax/homepage_controller.rb +7 -0
- data/app/controllers/hyrax/my/works_controller.rb +2 -21
- data/app/controllers/hyrax/permissions_controller.rb +4 -2
- data/app/controllers/hyrax/redirects_controller.rb +56 -0
- data/app/controllers/hyrax/single_use_links_viewer_controller.rb +2 -1
- data/app/controllers/hyrax/transcripts_controller.rb +31 -0
- data/app/controllers/hyrax/uploads_controller.rb +18 -9
- data/app/forms/concerns/hyrax/based_near_field_behavior.rb +77 -0
- data/app/forms/concerns/hyrax/flexible_form_behavior.rb +37 -0
- data/app/forms/concerns/hyrax/redirects_field_behavior.rb +95 -0
- data/app/forms/concerns/hyrax/transcripts_behavior.rb +40 -0
- data/app/forms/hyrax/forms/admin_set_form.rb +1 -1
- data/app/forms/hyrax/forms/administrative_set_form.rb +3 -0
- data/app/forms/hyrax/forms/batch_edit_form.rb +1 -3
- data/app/forms/hyrax/forms/batch_upload_form.rb +14 -0
- data/app/forms/hyrax/forms/file_set_edit_form.rb +1 -1
- data/app/forms/hyrax/forms/file_set_form.rb +6 -7
- data/app/forms/hyrax/forms/pcdm_collection_form.rb +17 -5
- data/app/forms/hyrax/forms/pcdm_object_form.rb +11 -3
- data/app/forms/hyrax/forms/resource_batch_edit_form.rb +8 -22
- data/app/forms/hyrax/forms/resource_form.rb +110 -10
- data/app/forms/hyrax/forms.rb +1 -0
- data/app/helpers/hyrax/attributes_helper.rb +109 -0
- data/app/helpers/hyrax/blacklight_override.rb +26 -0
- data/app/helpers/hyrax/collections_helper.rb +2 -0
- data/app/helpers/hyrax/file_set_form_helper.rb +24 -0
- data/app/helpers/hyrax/hyrax_helper_behavior.rb +51 -2
- data/app/helpers/hyrax/iiif_helper.rb +11 -1
- data/app/helpers/hyrax/permalink_helper.rb +37 -0
- data/app/helpers/hyrax/redirects_tab_helper.rb +29 -0
- data/app/helpers/hyrax/work_form_helper.rb +9 -5
- data/app/helpers/hyrax/works_helper.rb +14 -0
- data/app/indexers/concerns/hyrax/workflow_indexer.rb +30 -0
- data/app/indexers/hyrax/file_set_indexer.rb +1 -0
- data/app/indexers/hyrax/indexers/administrative_set_indexer.rb +2 -1
- data/app/indexers/hyrax/indexers/file_set_indexer.rb +6 -2
- data/app/indexers/hyrax/indexers/pcdm_collection_indexer.rb +11 -1
- data/app/indexers/hyrax/indexers/pcdm_object_indexer.rb +25 -4
- data/app/indexers/hyrax/indexers/redirects_indexer.rb +29 -0
- data/app/indexers/hyrax/indexers/resource_indexer.rb +4 -0
- data/app/indexers/hyrax/indexers.rb +2 -0
- data/app/inputs/controlled_vocabulary_input.rb +7 -1
- data/app/jobs/content_deposit_error_event_job.rb +14 -0
- data/app/jobs/create_work_job.rb +2 -0
- data/app/jobs/migrate_files_to_valkyrie_job.rb +7 -1
- data/app/models/batch_upload_item.rb +4 -0
- data/app/models/concerns/hyrax/ability/flexible_metadata_ability.rb +10 -0
- data/app/models/concerns/hyrax/ability.rb +3 -1
- data/app/models/concerns/hyrax/collection_behavior.rb +4 -0
- data/app/models/concerns/hyrax/file_set/transcripts.rb +16 -0
- data/app/models/concerns/hyrax/file_set_behavior.rb +9 -0
- data/app/models/concerns/hyrax/flexibility.rb +107 -0
- data/app/models/concerns/hyrax/redirects_normalization.rb +38 -0
- data/app/models/concerns/hyrax/solr_document/characterization.rb +1 -1
- data/app/models/concerns/hyrax/solr_document/metadata.rb +9 -0
- data/app/models/concerns/hyrax/solr_document/ordered_members.rb +4 -0
- data/app/models/concerns/hyrax/solr_document_behavior.rb +28 -6
- data/app/models/concerns/hyrax/suppressible.rb +1 -1
- data/app/models/concerns/hyrax/valkyrie_lazy_migration.rb +1 -1
- data/app/models/concerns/hyrax/with_embargoes_and_leases.rb +30 -0
- data/app/models/concerns/hyrax/work_behavior.rb +8 -0
- data/app/models/hyrax/administrative_set.rb +1 -1
- data/app/models/hyrax/change_set.rb +3 -1
- data/app/models/hyrax/embargo.rb +3 -1
- data/app/models/hyrax/file_set.rb +4 -2
- data/app/models/hyrax/flexible_schema.rb +219 -0
- data/app/models/hyrax/lease.rb +3 -1
- data/app/models/hyrax/pcdm_collection.rb +4 -1
- data/app/models/hyrax/redirect.rb +64 -0
- data/app/models/hyrax/redirect_path.rb +14 -0
- data/app/models/hyrax/resource.rb +22 -25
- data/app/models/hyrax/riiif/file.rb +43 -0
- data/app/models/hyrax/riiif/file_resolver.rb +65 -0
- data/app/models/hyrax/uploaded_file.rb +9 -0
- data/app/models/hyrax/virus_scanner.rb +16 -3
- data/app/models/hyrax/work.rb +4 -1
- data/app/models/job_io_wrapper.rb +12 -3
- data/app/models/user_mailbox.rb +3 -1
- data/app/presenters/hyrax/admin_set_presenter.rb +11 -0
- data/app/presenters/hyrax/annotates_content.rb +35 -0
- data/app/presenters/hyrax/collection_presenter.rb +5 -1
- data/app/presenters/hyrax/displays_content.rb +133 -0
- data/app/presenters/hyrax/displays_image.rb +11 -4
- data/app/presenters/hyrax/displays_transcripts.rb +59 -0
- data/app/presenters/hyrax/file_set_presenter.rb +8 -18
- data/app/presenters/hyrax/google_scholar_presenter.rb +39 -0
- data/app/presenters/hyrax/iiif_manifest_presenter.rb +22 -4
- data/app/presenters/hyrax/missing_method_behavior.rb +15 -0
- data/app/presenters/hyrax/pcdm_member_presenter_factory.rb +2 -4
- data/app/presenters/hyrax/work_show_presenter.rb +56 -14
- data/app/renderers/hyrax/renderers/attribute_renderer.rb +6 -2
- data/app/renderers/hyrax/renderers/license_attribute_renderer.rb +10 -10
- data/app/renderers/hyrax/renderers/redirects_label_attribute_renderer.rb +25 -0
- data/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb +10 -11
- data/app/search_builders/hyrax/dashboard/nested_collections_search_builder.rb +1 -5
- data/app/search_builders/hyrax/filter_by_type.rb +1 -1
- data/app/services/hyrax/action/create_valkyrie_work.rb +3 -2
- data/app/services/hyrax/authority_rendering_helper.rb +28 -0
- data/app/services/hyrax/authority_service.rb +107 -0
- data/app/services/hyrax/callbacks.rb +2 -2
- data/app/services/hyrax/collections/nested_collection_query_service.rb +9 -3
- data/app/services/hyrax/collections_service.rb +17 -0
- data/app/services/hyrax/custom_queries/find_by_property_value.rb +89 -0
- data/app/services/hyrax/edit_permissions_service.rb +4 -4
- data/app/services/hyrax/file_set_type_service.rb +12 -4
- data/app/services/hyrax/flexible_schema_validator_service.rb +153 -0
- data/app/services/hyrax/flexible_schema_validators/class_validator.rb +123 -0
- data/app/services/hyrax/flexible_schema_validators/core_metadata_validator.rb +211 -0
- data/app/services/hyrax/flexible_schema_validators/existing_records_validator.rb +83 -0
- data/app/services/hyrax/flexible_schema_validators/redirects_validator.rb +116 -0
- data/app/services/hyrax/flexible_schema_validators/schema_validator.rb +34 -0
- data/app/services/hyrax/flexible_schema_validators/sort_properties_validator.rb +54 -0
- data/app/services/hyrax/license_service.rb +1 -1
- data/app/services/hyrax/listeners/metadata_index_listener.rb +11 -0
- data/app/services/hyrax/m3_profile_editor.rb +32 -0
- data/app/services/hyrax/m3_schema_loader.rb +119 -0
- data/app/services/hyrax/manifest_builder_service.rb +18 -24
- data/app/services/hyrax/permalink_path.rb +25 -0
- data/app/services/hyrax/qa_select_service.rb +9 -5
- data/app/services/hyrax/redirect_path_normalizer.rb +58 -0
- data/app/services/hyrax/redirects_lookup.rb +59 -0
- data/app/services/hyrax/resource_permissions_visibility_propagator.rb +54 -0
- data/app/services/hyrax/resource_types_service.rb +3 -20
- data/app/services/hyrax/rights_statement_service.rb +1 -1
- data/app/services/hyrax/schema_loader.rb +205 -0
- data/app/services/hyrax/search_service.rb +1 -1
- data/app/services/hyrax/simple_schema_loader.rb +28 -127
- data/app/services/hyrax/solr_service.rb +39 -2
- data/app/services/hyrax/tolerant_select_service.rb +5 -3
- data/app/services/hyrax/valkyrie_upload.rb +2 -2
- data/app/services/hyrax/visibility_propagator.rb +4 -1
- data/app/services/hyrax/work_uploads_handler.rb +17 -9
- data/app/services/hyrax/workflow/workflow_factory.rb +5 -4
- data/app/services/migrate_resource_service.rb +7 -1
- data/app/uploaders/hyrax/uploaded_file_uploader.rb +2 -2
- data/app/utils/hyrax/data_destroyers/collection_branding_destroyer.rb +1 -1
- data/app/utils/hyrax/required_data_seeder.rb +1 -0
- data/app/utils/hyrax/required_data_seeders/collection_type_seeder.rb +1 -1
- data/app/utils/hyrax/required_data_seeders/flexible_profile_seeder.rb +28 -0
- data/app/validators/hyrax/controlled_vocabulary_validator.rb +64 -0
- data/app/validators/hyrax/redirect_validator.rb +128 -0
- data/app/views/catalog/_thumbnail_list_default.html.erb +2 -2
- data/app/views/collections/edit_fields/_schema_version.html.erb +1 -0
- data/app/views/hyrax/admin/admin_sets/_form_metadata.html.erb +24 -2
- data/app/views/hyrax/admin/admin_sets/_show_document_list_row.html.erb +1 -1
- data/app/views/hyrax/admin/admin_sets/show.html.erb +1 -1
- data/app/views/hyrax/admin/analytics/_analytics_error.html.erb +42 -0
- data/app/views/hyrax/admin/analytics/collection_reports/index.html.erb +11 -9
- data/app/views/hyrax/admin/analytics/work_reports/index.html.erb +60 -57
- data/app/views/hyrax/admin/features/index.html.erb +1 -1
- data/app/views/hyrax/admin/metadata_profiles/_import_modal.html.erb +20 -0
- data/app/views/hyrax/admin/metadata_profiles/index.html.erb +54 -0
- data/app/views/hyrax/base/_attribute_rows.html.erb +4 -21
- data/app/views/hyrax/base/_citations.html.erb +1 -0
- data/app/views/hyrax/base/_currently_shared.html.erb +2 -1
- data/app/views/hyrax/base/_file_manager_thumbnail.html.erb +1 -1
- data/app/views/hyrax/base/_form_member_of_collections.html.erb +6 -6
- data/app/views/hyrax/base/_form_redirects.html.erb +125 -0
- data/app/views/hyrax/base/_form_share.html.erb +7 -2
- data/app/views/hyrax/base/_member.html.erb +1 -1
- data/app/views/hyrax/base/_social_media.html.erb +1 -1
- data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +1 -1
- data/app/views/hyrax/base/show.html.erb +3 -0
- data/app/views/hyrax/collections/_default_group.html.erb +3 -0
- data/app/views/hyrax/collections/_list_collections.html.erb +3 -0
- data/app/views/hyrax/collections/_list_works.html.erb +1 -1
- data/app/views/hyrax/collections/_show_document_list_row.html.erb +1 -1
- data/app/views/hyrax/collections/show.html.erb +4 -0
- data/app/views/hyrax/dashboard/_sidebar.html.erb +4 -2
- data/app/views/hyrax/dashboard/collections/_button_for_update_collection.html.erb +2 -1
- data/app/views/hyrax/dashboard/collections/_default_group.html.erb +3 -0
- data/app/views/hyrax/dashboard/collections/_form.html.erb +17 -0
- data/app/views/hyrax/dashboard/collections/_form_for_select_collection.html.erb +7 -10
- data/app/views/hyrax/dashboard/collections/_list_collections.html.erb +3 -0
- data/app/views/hyrax/dashboard/collections/_list_works.html.erb +1 -1
- data/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +1 -1
- data/app/views/hyrax/dashboard/profiles/_edit_primary.html.erb +1 -8
- data/app/views/hyrax/dashboard/profiles/_trophy_edit.html.erb +1 -1
- data/app/views/hyrax/dashboard/profiles/show.html.erb +5 -5
- data/app/views/hyrax/dashboard/sidebar/_metadata.html.erb +11 -0
- data/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +1 -0
- data/app/views/hyrax/dashboard/works/_default_group.html.erb +3 -0
- data/app/views/hyrax/dashboard/works/_list_works.html.erb +4 -2
- data/app/views/hyrax/file_sets/_form.html.erb +16 -3
- data/app/views/hyrax/file_sets/_metadata.html.erb +35 -0
- data/app/views/hyrax/file_sets/_valkyrie_form.html.erb +37 -0
- data/app/views/hyrax/file_sets/edit.html.erb +14 -8
- data/app/views/hyrax/file_sets/media_display/_audio.html.erb +4 -0
- data/app/views/hyrax/file_sets/media_display/_image.html.erb +2 -2
- data/app/views/hyrax/file_sets/media_display/_video.html.erb +4 -0
- data/app/views/hyrax/homepage/_explore_collections.html.erb +1 -1
- data/app/views/hyrax/homepage/_featured_fields.html.erb +1 -1
- data/app/views/hyrax/homepage/_recent_document.html.erb +1 -1
- data/app/views/hyrax/homepage/robots.text.erb +17 -0
- data/app/views/hyrax/my/collections/_default_group.html.erb +3 -0
- data/app/views/hyrax/my/collections/_list_collections.html.erb +3 -0
- data/app/views/hyrax/my/collections/_modal_add_subcollection.html.erb +2 -2
- data/app/views/hyrax/my/collections/_modal_add_to_collection.html.erb +2 -2
- data/app/views/hyrax/my/works/_default_group.html.erb +3 -0
- data/app/views/hyrax/my/works/_list_works.html.erb +5 -2
- data/app/views/hyrax/shared/_copy_permalink.html.erb +10 -0
- data/app/views/hyrax/users/_user_info.html.erb +1 -6
- data/app/views/layouts/_head_tag_content.html.erb +2 -0
- data/app/views/layouts/hyrax/dashboard.html.erb +2 -1
- data/app/views/records/edit_fields/_contexts.html.erb +1 -0
- data/app/views/records/edit_fields/_license.html.erb +17 -5
- data/app/views/records/edit_fields/_resource_type.html.erb +16 -2
- data/app/views/records/edit_fields/_rights_statement.html.erb +17 -5
- data/app/views/records/edit_fields/_schema_version.html.erb +1 -0
- data/app/views/records/edit_fields/_transcript_ids.html.erb +18 -0
- data/app/views/records/show_fields/_rights.html.erb +1 -1
- data/app/views/shared/_citations.html.erb +46 -31
- data/app/views/shared/_schema_version.html.erb +38 -0
- data/bin/dev-entrypoint.sh +14 -4
- data/chart/hyrax/Chart.yaml +4 -4
- data/chart/hyrax/templates/ingress.yaml +3 -0
- data/chart/hyrax/values.yaml +10 -8
- data/config/features.rb +27 -0
- data/config/initializers/blacklight_dynamic_sitemap.rb +43 -0
- data/config/initializers/deprecation_patch.rb +27 -0
- data/config/initializers/hydra_works.rb +3 -0
- data/config/initializers/i18n_extensions.rb +197 -0
- data/config/initializers/storage_adapter_initializer.rb +15 -9
- data/config/locales/hyrax.de.yml +172 -54
- data/config/locales/hyrax.en.yml +183 -66
- data/config/locales/hyrax.es.yml +174 -49
- data/config/locales/hyrax.fr.yml +169 -45
- data/config/locales/hyrax.it.yml +172 -48
- data/config/locales/hyrax.pt-BR.yml +172 -54
- data/config/locales/hyrax.zh.yml +145 -21
- data/config/metadata/basic_metadata.yaml +66 -0
- data/config/metadata/batch_edit_metadata.yaml +119 -0
- data/config/metadata/file_set_metadata.yaml +19 -0
- data/config/metadata/redirects.yaml +15 -0
- data/config/metadata_profiles/m3_json_schema.json +487 -0
- data/config/metadata_profiles/m3_profile.yaml +954 -0
- data/config/routes.rb +9 -0
- data/docker-compose-allinson.yml +176 -0
- data/docker-compose-dassie.yml +14 -6
- data/docker-compose-koppie.yml +18 -10
- data/docker-compose-sirenia.yml +20 -10
- data/documentation/copy_permalink.md +29 -0
- data/documentation/developing-your-hyrax-based-app.md +2 -2
- data/documentation/file-ingest-characterization.md +763 -0
- data/documentation/flexible_metadata.md +113 -0
- data/documentation/forms/field_behaviors.md +297 -0
- data/documentation/redirects.md +428 -0
- data/hyrax.gemspec +7 -2
- data/lib/freyja/metadata_adapter.rb +1 -1
- data/lib/freyja/persister.rb +25 -1
- data/lib/generators/hyrax/collection_resource/collection_resource_generator.rb +2 -2
- data/lib/generators/hyrax/collection_resource/templates/collection.rb.erb +5 -1
- data/lib/generators/hyrax/collection_resource/templates/collection_form.rb.erb +5 -1
- data/lib/generators/hyrax/collection_resource/templates/collection_indexer.rb.erb +6 -1
- data/lib/generators/hyrax/iiif_viewer/USAGE +22 -0
- data/lib/generators/hyrax/iiif_viewer/iiif_viewer_generator.rb +49 -0
- data/lib/generators/hyrax/iiif_viewer/templates/_clover.html.erb +7 -0
- data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.css +3328 -0
- data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.html +16 -0
- data/lib/generators/hyrax/iiif_viewer/templates/clover/clover.js +237 -0
- data/lib/generators/hyrax/install_generator.rb +25 -1
- data/lib/generators/hyrax/riiif_generator.rb +1 -1
- data/lib/generators/hyrax/templates/app/views/blacklight_dynamic_sitemap/sitemap/show.xml.builder +22 -0
- data/lib/generators/hyrax/templates/config/clamav.rb +2 -0
- data/lib/generators/hyrax/templates/config/initializers/riiif.rb +4 -80
- data/lib/generators/hyrax/templates/db/migrate/20240606205215_create_hyrax_flexible_schemas.rb.erb +9 -0
- data/lib/generators/hyrax/templates/db/migrate/20240606205216_add_contexts_to_hyrax_flexible_schemas.rb.erb +5 -0
- data/lib/generators/hyrax/templates/db/migrate/20260430000001_create_hyrax_redirect_paths.rb.erb +22 -0
- data/lib/generators/hyrax/templates/db/migrate/20260521003627_add_additional_redirect_info.rb.erb +39 -0
- data/lib/generators/hyrax/templates/package.json +1 -1
- data/lib/generators/hyrax/templates/uv.html +60 -82
- data/lib/generators/hyrax/work/templates/indexer.rb.erb +1 -1
- data/lib/generators/hyrax/work/templates/model.rb.erb +5 -1
- data/lib/generators/hyrax/work_resource/templates/form.rb.erb +5 -2
- data/lib/generators/hyrax/work_resource/templates/indexer.rb.erb +6 -2
- data/lib/generators/hyrax/work_resource/templates/work.rb.erb +5 -2
- data/lib/generators/hyrax/work_resource/work_resource_generator.rb +1 -0
- data/lib/hyrax/active_fedora_dummy_model.rb +6 -0
- data/lib/hyrax/configuration.rb +197 -3
- data/lib/hyrax/deprecation.rb +31 -0
- data/lib/hyrax/engine.rb +2 -0
- data/lib/hyrax/form_fields.rb +17 -5
- data/lib/hyrax/indexer.rb +31 -2
- data/lib/hyrax/resource_sync/resource_list_writer.rb +3 -0
- data/lib/hyrax/schema.rb +15 -4
- data/lib/hyrax/specs/shared_specs/factories/administrative_sets.rb +12 -0
- data/lib/hyrax/specs/shared_specs/factories/hyrax_embargo.rb +1 -1
- data/lib/hyrax/specs/shared_specs/factories/hyrax_file_set.rb +13 -0
- data/lib/hyrax/specs/shared_specs/factories/hyrax_lease.rb +5 -1
- data/lib/hyrax/specs/shared_specs/factories/hyrax_work.rb +14 -0
- data/lib/hyrax/specs/shared_specs/simple_work.rb +41 -0
- data/lib/hyrax/specs/shared_specs.rb +1 -0
- data/lib/hyrax/transactions/collection_create.rb +2 -1
- data/lib/hyrax/transactions/collection_destroy.rb +1 -0
- data/lib/hyrax/transactions/collection_update.rb +2 -1
- data/lib/hyrax/transactions/container.rb +28 -0
- data/lib/hyrax/transactions/steps/apply_permission_template_on_update.rb +65 -0
- data/lib/hyrax/transactions/steps/apply_workflow_on_admin_set_change.rb +97 -0
- data/lib/hyrax/transactions/steps/ensure_admin_set.rb +1 -1
- data/lib/hyrax/transactions/steps/remove_redirect_paths.rb +35 -0
- data/lib/hyrax/transactions/steps/save.rb +10 -0
- data/lib/hyrax/transactions/steps/set_default_admin_set.rb +1 -1
- data/lib/hyrax/transactions/steps/sync_redirect_paths.rb +141 -0
- data/lib/hyrax/transactions/work_create.rb +2 -1
- data/lib/hyrax/transactions/work_destroy.rb +1 -0
- data/lib/hyrax/transactions/work_update.rb +4 -1
- data/lib/hyrax/version.rb +1 -1
- data/lib/hyrax.rb +61 -0
- data/lib/tasks/m3_profile_cleanup.rake +35 -0
- data/template.rb +4 -1
- metadata +313 -19
- data/.dassie/public/robots.txt +0 -1
- data/.koppie/public/robots.txt +0 -1
- data/app/forms/concerns/hyrax/basic_metadata_form_fields_behavior.rb +0 -39
- data/app/views/catalog/_thumbnail_list_collection.html.erb +0 -4
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
# Handles class-related validations for flexible metadata profiles
|
|
6
|
+
class ClassValidator
|
|
7
|
+
# @param profile [Hash] M3 profile data
|
|
8
|
+
# @param required_classes [Array<String>] Foundational classes that must be present
|
|
9
|
+
# @param errors [Array<String>] Array to append validation errors to
|
|
10
|
+
def initialize(profile, required_classes, errors)
|
|
11
|
+
@profile = profile
|
|
12
|
+
@required_classes = required_classes
|
|
13
|
+
@errors = errors
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Validates that referenced classes are registered Hyrax curation concern
|
|
17
|
+
# types and that Valkyrie models use the correct `...Resource` naming
|
|
18
|
+
# convention when applicable.
|
|
19
|
+
#
|
|
20
|
+
# @return [void]
|
|
21
|
+
def validate_availability!
|
|
22
|
+
classes_to_validate = all_profile_classes - @required_classes
|
|
23
|
+
invalid_classes = []
|
|
24
|
+
mismatched_valkyrie_classes = []
|
|
25
|
+
|
|
26
|
+
classes_to_validate.each do |klass|
|
|
27
|
+
validate_class(klass, invalid_classes, mismatched_valkyrie_classes)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
report_mismatched_classes(mismatched_valkyrie_classes)
|
|
31
|
+
report_invalid_classes(invalid_classes)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Validates that all classes referenced within property `available_on`
|
|
35
|
+
# definitions are themselves defined in the top-level `classes` section of
|
|
36
|
+
# the profile.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
def validate_references!
|
|
40
|
+
properties = @profile['properties'] || {}
|
|
41
|
+
|
|
42
|
+
referenced_classes = properties.values.flat_map do |prop|
|
|
43
|
+
prop.dig('available_on', 'class')
|
|
44
|
+
end.compact.uniq
|
|
45
|
+
|
|
46
|
+
undefined_classes = referenced_classes - @profile['classes'].keys
|
|
47
|
+
|
|
48
|
+
return if undefined_classes.empty?
|
|
49
|
+
|
|
50
|
+
@errors << "Classes referenced in `available_on` but not defined in `classes`: #{undefined_classes.join(', ')}."
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# Gathers all unique class names from both the top-level `classes`
|
|
56
|
+
# definition and all `available_on` property references.
|
|
57
|
+
#
|
|
58
|
+
# @return [Array<String>]
|
|
59
|
+
def all_profile_classes
|
|
60
|
+
profile_classes = @profile.fetch('classes', {}).keys
|
|
61
|
+
properties = @profile['properties'] || {}
|
|
62
|
+
available_on_classes = properties.values.flat_map do |prop|
|
|
63
|
+
prop.dig('available_on', 'class')
|
|
64
|
+
end.compact
|
|
65
|
+
|
|
66
|
+
clean_class_names(profile_classes + available_on_classes).uniq
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def clean_class_names(names)
|
|
70
|
+
names.map { |name| name.to_s.strip.gsub(/^::/, '') }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Validates a single class, checking for registration as a curation concern
|
|
74
|
+
# and for Valkyrie naming mismatches using the Valkyrie resolver.
|
|
75
|
+
#
|
|
76
|
+
# @param klass [String] the class name to validate
|
|
77
|
+
# @param invalid_classes [Array<String>] an array to append invalid class errors to
|
|
78
|
+
# @param mismatched_valkyrie_classes [Array<Hash>] an array to append Valkyrie mismatch errors to
|
|
79
|
+
# @return [void]
|
|
80
|
+
def validate_class(klass, invalid_classes, mismatched_valkyrie_classes)
|
|
81
|
+
base_class_name = klass.gsub(/(?<=.)Resource$/, '')
|
|
82
|
+
unless Hyrax.config.registered_curation_concern_types.include?(base_class_name)
|
|
83
|
+
invalid_classes << klass
|
|
84
|
+
return
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
begin
|
|
88
|
+
expected_valkyrie_class = Valkyrie.config.resource_class_resolver.call(base_class_name)
|
|
89
|
+
expected_class_name = expected_valkyrie_class.to_s
|
|
90
|
+
|
|
91
|
+
mismatched_valkyrie_classes << { non_resource: klass, resource: expected_class_name } if klass != expected_class_name
|
|
92
|
+
rescue NameError
|
|
93
|
+
# This occurs if a registered concern doesn't have a loadable backing class,
|
|
94
|
+
# which is an invalid state.
|
|
95
|
+
invalid_classes << klass
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Appends a formatted error message for any Valkyrie naming mismatches.
|
|
100
|
+
#
|
|
101
|
+
# @param mismatched_classes [Array<Hash>]
|
|
102
|
+
# @return [void]
|
|
103
|
+
def report_mismatched_classes(mismatched_classes)
|
|
104
|
+
return if mismatched_classes.empty?
|
|
105
|
+
|
|
106
|
+
message = mismatched_classes.map do |mismatch|
|
|
107
|
+
"'#{mismatch[:non_resource]}' should be '#{mismatch[:resource]}'"
|
|
108
|
+
end.join(', ')
|
|
109
|
+
@errors << "Mismatched Valkyrie classes found: #{message}."
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Appends a formatted error message for any invalid classes.
|
|
113
|
+
#
|
|
114
|
+
# @param invalid_classes [Array<String>]
|
|
115
|
+
# @return [void]
|
|
116
|
+
def report_invalid_classes(invalid_classes)
|
|
117
|
+
return if invalid_classes.empty?
|
|
118
|
+
|
|
119
|
+
@errors << "Invalid classes: #{invalid_classes.join(', ')}."
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
##
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# Validates the core metadata properties of a flexible metadata profile.
|
|
9
|
+
class CoreMetadataValidator
|
|
10
|
+
##
|
|
11
|
+
# @param profile [Hash] the flexible metadata profile
|
|
12
|
+
# @param errors [Array<String>] an array to append errors to
|
|
13
|
+
def initialize(profile:, errors:)
|
|
14
|
+
@profile = profile
|
|
15
|
+
@errors = errors
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Validate the profile against the core metadata requirements and append
|
|
19
|
+
# any human-readable error messages to {#errors}.
|
|
20
|
+
#
|
|
21
|
+
# @return [void]
|
|
22
|
+
def validate!
|
|
23
|
+
core_metadata['attributes'].each do |property, config|
|
|
24
|
+
next unless validate_property_exists(property)
|
|
25
|
+
|
|
26
|
+
validate_property_multi_value(property, config)
|
|
27
|
+
validate_property_indexing(property, config)
|
|
28
|
+
validate_property_predicate(property, config)
|
|
29
|
+
validate_property_available_on(property)
|
|
30
|
+
validate_property_cardinality(property, config)
|
|
31
|
+
end
|
|
32
|
+
validate_keyword_property
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
attr_reader :profile, :errors
|
|
38
|
+
|
|
39
|
+
# Load and memoize the core metadata definition from
|
|
40
|
+
# `config/metadata/core_metadata.yaml`.
|
|
41
|
+
#
|
|
42
|
+
# @return [Hash] the core metadata configuration with indifferent access
|
|
43
|
+
def core_metadata
|
|
44
|
+
return @core_metadata if @core_metadata
|
|
45
|
+
|
|
46
|
+
@core_metadata = YAML.safe_load(
|
|
47
|
+
File.read(Hyrax::Engine.root.join('config', 'metadata', 'core_metadata.yaml'))
|
|
48
|
+
).with_indifferent_access
|
|
49
|
+
|
|
50
|
+
# Ensure the `creator` attribute is always treated as core metadata even
|
|
51
|
+
# when it is not present in the YAML definition shipped with Hyrax.
|
|
52
|
+
@core_metadata['attributes'] ||= {}
|
|
53
|
+
|
|
54
|
+
@core_metadata['attributes']['creator'] ||= {
|
|
55
|
+
'type' => 'string',
|
|
56
|
+
'multiple' => true,
|
|
57
|
+
'index_keys' => ['creator_sim', 'creator_tesim'],
|
|
58
|
+
'predicate' => 'http://purl.org/dc/elements/1.1/creator'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@core_metadata
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Memoized convenience accessor that returns the class keys defined in
|
|
65
|
+
# the profile.
|
|
66
|
+
#
|
|
67
|
+
# @return [Array<String>]
|
|
68
|
+
def defined_classes
|
|
69
|
+
@defined_classes ||= profile['classes'].keys
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Ensures the given property is present in the profile's `properties`
|
|
73
|
+
# section.
|
|
74
|
+
#
|
|
75
|
+
# @param property [String, Symbol] the property name
|
|
76
|
+
# @return [Boolean] true if the property exists, otherwise false
|
|
77
|
+
def validate_property_exists(property)
|
|
78
|
+
return true if profile['properties'][property].present?
|
|
79
|
+
|
|
80
|
+
errors << "Missing required property: #{property}."
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Validate that the property's `data_type` matches the expected type
|
|
85
|
+
# based on the core metadata's `multiple` setting.
|
|
86
|
+
#
|
|
87
|
+
# @param property [String, Symbol] the property name
|
|
88
|
+
# @param config [Hash] the core metadata configuration for the property
|
|
89
|
+
# @return [void]
|
|
90
|
+
def validate_property_multi_value(property, config)
|
|
91
|
+
return unless config.key?("multiple")
|
|
92
|
+
|
|
93
|
+
property_config = profile.dig('properties', property) || {}
|
|
94
|
+
|
|
95
|
+
required_data_type = config['multiple'] ? 'array' : 'string'
|
|
96
|
+
|
|
97
|
+
actual_data_type = determine_data_type_from_config(property_config)
|
|
98
|
+
|
|
99
|
+
return if actual_data_type == required_data_type
|
|
100
|
+
|
|
101
|
+
errors << "Property '#{property}' must have data_type set to '#{required_data_type}'."
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Determine the property's effective data type from its configuration.
|
|
105
|
+
#
|
|
106
|
+
# @param property_config [Hash] the property's configuration from the profile
|
|
107
|
+
# @return [String] either 'array' or 'string'
|
|
108
|
+
def determine_data_type_from_config(property_config)
|
|
109
|
+
if property_config['data_type']
|
|
110
|
+
property_config['data_type']
|
|
111
|
+
elsif property_config['multi_value']
|
|
112
|
+
'array'
|
|
113
|
+
else
|
|
114
|
+
'string'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Validate that the profile includes all indexing keys required by the
|
|
119
|
+
# core metadata configuration.
|
|
120
|
+
#
|
|
121
|
+
# @param property [String, Symbol]
|
|
122
|
+
# @param config [Hash]
|
|
123
|
+
# @return [void]
|
|
124
|
+
def validate_property_indexing(property, config)
|
|
125
|
+
return unless config.key?('index_keys')
|
|
126
|
+
|
|
127
|
+
profile_indexing = profile.dig('properties', property, 'indexing') || []
|
|
128
|
+
missing_keys = config['index_keys'] - profile_indexing
|
|
129
|
+
|
|
130
|
+
return if missing_keys.empty?
|
|
131
|
+
|
|
132
|
+
errors << "Property '#{property}' is missing required indexing: #{missing_keys.join(', ')}."
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Ensures that the property's predicate matches the core metadata definition.
|
|
136
|
+
#
|
|
137
|
+
# @param property [String, Symbol]
|
|
138
|
+
# @param config [Hash]
|
|
139
|
+
# @return [void]
|
|
140
|
+
def validate_property_predicate(property, config)
|
|
141
|
+
return unless config.key?('predicate')
|
|
142
|
+
return if profile.dig('properties', property, 'property_uri') == config['predicate']
|
|
143
|
+
|
|
144
|
+
errors << "Property '#{property}' must have property_uri set to #{config['predicate']}."
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Validates that if the `keyword` property is present, it is correctly
|
|
148
|
+
# configured as a multi-valued field.
|
|
149
|
+
#
|
|
150
|
+
# @return [void]
|
|
151
|
+
def validate_keyword_property
|
|
152
|
+
keyword_prop = profile.dig('properties', 'keyword')
|
|
153
|
+
return unless keyword_prop
|
|
154
|
+
|
|
155
|
+
return if keyword_prop['data_type'] == 'array'
|
|
156
|
+
|
|
157
|
+
errors << "Property 'keyword' must have data_type set to 'array'."
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Checks that the property is available on all classes defined in the profile.
|
|
161
|
+
# A property entry with `name: <property>` is treated as an alias and counts
|
|
162
|
+
# toward coverage for the resolved name.
|
|
163
|
+
#
|
|
164
|
+
# @param property [String, Symbol]
|
|
165
|
+
# @return [void]
|
|
166
|
+
def validate_property_available_on(property)
|
|
167
|
+
available_on_classes = classes_covered_by_resolved_name(property.to_s)
|
|
168
|
+
missing_classes = defined_classes - available_on_classes
|
|
169
|
+
|
|
170
|
+
return if missing_classes.empty?
|
|
171
|
+
errors << "Property '#{property}' must be available on all classes, but is missing from: #{missing_classes.join(', ')}."
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Returns all classes covered by any profile property whose resolved name
|
|
175
|
+
# matches +property_name+ (either directly or via the `name` override key).
|
|
176
|
+
#
|
|
177
|
+
# @param property_name [String]
|
|
178
|
+
# @return [Array<String>]
|
|
179
|
+
def classes_covered_by_resolved_name(property_name)
|
|
180
|
+
profile['properties'].each_with_object([]) do |(key, config), covered|
|
|
181
|
+
resolved = (config['name'] || key).to_s
|
|
182
|
+
next unless resolved == property_name
|
|
183
|
+
|
|
184
|
+
covered.concat(Array(config.dig('available_on', 'class')))
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Validates the property's cardinality, ensuring that `title` is required
|
|
189
|
+
# (i.e., has a minimum cardinality of 1).
|
|
190
|
+
#
|
|
191
|
+
# @param property [String, Symbol]
|
|
192
|
+
# @param _config [Hash] the core metadata configuration for the property (unused)
|
|
193
|
+
# @return [void]
|
|
194
|
+
def validate_property_cardinality(property, _config)
|
|
195
|
+
# Ensure that the `title` property is always required by enforcing
|
|
196
|
+
# a cardinality minimum of at least 1. According to the M3 profile
|
|
197
|
+
# specification, `cardinality.minimum` > 0 is interpreted as
|
|
198
|
+
# "required".
|
|
199
|
+
return unless property.to_s == 'title'
|
|
200
|
+
|
|
201
|
+
minimum = profile.dig('properties', property, 'cardinality', 'minimum')
|
|
202
|
+
|
|
203
|
+
# Treat missing `cardinality` or `minimum` as 0 (i.e., not required).
|
|
204
|
+
required = minimum.to_i.positive?
|
|
205
|
+
return if required
|
|
206
|
+
|
|
207
|
+
errors << "Property 'title' must have a cardinality minimum of at least 1."
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
# Validates that classes with existing records in the repository are not removed from the profile.
|
|
6
|
+
class ExistingRecordsValidator
|
|
7
|
+
# @param profile [Hash] M3 profile data
|
|
8
|
+
# @param required_classes [Array<String>] Foundational classes that must be present
|
|
9
|
+
# @param errors [Array<String>] Array to append validation errors to
|
|
10
|
+
def initialize(profile, required_classes, errors)
|
|
11
|
+
@profile = profile
|
|
12
|
+
@required_classes = required_classes
|
|
13
|
+
@errors = errors
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Validates that no classes with existing records in the repository have been
|
|
17
|
+
# removed from the profile.
|
|
18
|
+
#
|
|
19
|
+
# @return [void]
|
|
20
|
+
def validate!
|
|
21
|
+
profile_classes_set = Set.new(@profile.fetch('classes', {}).keys)
|
|
22
|
+
classes_with_records = []
|
|
23
|
+
potential_existing_classes.each do |model_class|
|
|
24
|
+
model_identifier = model_class.to_s
|
|
25
|
+
counterpart_identifier = counterpart_for(model_identifier)
|
|
26
|
+
|
|
27
|
+
# If this model or its counterpart is in the profile, we don't need to check it for removal.
|
|
28
|
+
next if profile_classes_set.include?(model_identifier) || profile_classes_set.include?(counterpart_identifier)
|
|
29
|
+
|
|
30
|
+
# If it's not in the profile, check if it has records.
|
|
31
|
+
classes_with_records << model_identifier if model_has_records?(model_class, model_identifier)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return if classes_with_records.empty?
|
|
35
|
+
|
|
36
|
+
@errors << "Classes with existing records cannot be removed from the profile: #{classes_with_records.uniq.join(', ')}."
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# Determines the counterpart model name (e.g., Image -> ImageResource).
|
|
42
|
+
def counterpart_for(model_identifier)
|
|
43
|
+
return unless defined?(Wings)
|
|
44
|
+
|
|
45
|
+
klass = model_identifier.safe_constantize
|
|
46
|
+
return if klass.blank?
|
|
47
|
+
|
|
48
|
+
Wings::ModelRegistry.lookup(klass).to_s
|
|
49
|
+
rescue NameError
|
|
50
|
+
# This can happen if a class is not loadable,
|
|
51
|
+
# or if a counterpart model does not exist.
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Queries the repository to see if a given model has any records.
|
|
56
|
+
def model_has_records?(model_class, class_name)
|
|
57
|
+
Hyrax.query_service.count_all_of_model(model: model_class).positive?
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
Rails.logger.error "Error checking records for #{class_name}: #{e.message}"
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Gathers all unique, canonical model classes that could potentially have records.
|
|
64
|
+
# @return [Array<Class>]
|
|
65
|
+
def potential_existing_classes
|
|
66
|
+
return @models if @models.present?
|
|
67
|
+
@models = @required_classes.clone.map(&:safe_constantize)
|
|
68
|
+
Hyrax.config.registered_curation_concern_types.each do |concern_type|
|
|
69
|
+
resource = concern_type.match?(/Resource$/) ? concern_type : "#{concern_type}Resource"
|
|
70
|
+
resource.safe_constantize
|
|
71
|
+
@models << Valkyrie.config.resource_class_resolver.call(concern_type)
|
|
72
|
+
rescue NameError, LoadError
|
|
73
|
+
# This can happen if a concern is registered but its class is not loadable.
|
|
74
|
+
# We can safely ignore it, as it couldn't have records anyway.
|
|
75
|
+
Rails.logger.warn "Could not resolve model class for registered concern: #{concern_type}"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@models.uniq!
|
|
79
|
+
@models
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
##
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# Validates the `redirects` property in an m3 profile against the
|
|
9
|
+
# two-layer feature gating (config + Flipflop):
|
|
10
|
+
#
|
|
11
|
+
# | config | flipflop | property | result |
|
|
12
|
+
# |--------|----------|----------|-------------------------------------|
|
|
13
|
+
# | off | n/a | present | warn (property will be ignored) |
|
|
14
|
+
# | off | n/a | absent | silent |
|
|
15
|
+
# | on | off | present | warn (property is loaded but unused)|
|
|
16
|
+
# | on | off | absent | silent |
|
|
17
|
+
# | on | on | absent | error (property is required) |
|
|
18
|
+
# | on | on | present | check available_on.class lists at |
|
|
19
|
+
# | | | | least one work or collection class |
|
|
20
|
+
# | | | | declared in this profile's classes |
|
|
21
|
+
class RedirectsValidator
|
|
22
|
+
##
|
|
23
|
+
# @param profile [Hash] the flexible metadata profile
|
|
24
|
+
# @param errors [Array<String>] an array to append errors to
|
|
25
|
+
# @param warnings [Array<String>] an array to append warnings to
|
|
26
|
+
def initialize(profile:, errors:, warnings: [])
|
|
27
|
+
@profile = profile
|
|
28
|
+
@errors = errors
|
|
29
|
+
@warnings = warnings
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Validate the profile against the redirects requirements and append
|
|
33
|
+
# any human-readable error messages to {#errors} (or warnings to
|
|
34
|
+
# {#warnings} for the dead-property cases).
|
|
35
|
+
#
|
|
36
|
+
# @return [void]
|
|
37
|
+
def validate!
|
|
38
|
+
return validate_when_config_off unless Hyrax.config.redirects_enabled?
|
|
39
|
+
return validate_when_flipflop_off unless Flipflop.redirects?
|
|
40
|
+
|
|
41
|
+
validate_when_enabled
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def redirects_property
|
|
47
|
+
@redirects_property ||= @profile&.dig('properties', 'redirects')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def validate_when_config_off
|
|
51
|
+
return if redirects_property.blank?
|
|
52
|
+
@warnings << I18n.t('hyrax.flexible_schema_validators.redirects_validator.warnings.config_disabled')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate_when_flipflop_off
|
|
56
|
+
return if redirects_property.blank?
|
|
57
|
+
@warnings << I18n.t('hyrax.flexible_schema_validators.redirects_validator.warnings.flipflop_disabled')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def validate_when_enabled
|
|
61
|
+
if redirects_property.blank?
|
|
62
|
+
@errors << I18n.t('hyrax.flexible_schema_validators.redirects_validator.errors.property_required')
|
|
63
|
+
return
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@errors << I18n.t('hyrax.flexible_schema_validators.redirects_validator.errors.invalid_type', actual_type: redirects_property['type'].inspect) unless redirects_property['type'].to_s == 'hash'
|
|
67
|
+
|
|
68
|
+
available_on = clean(Array(redirects_property.dig('available_on', 'class')))
|
|
69
|
+
return if (available_on & profile_work_or_collection_classes).any?
|
|
70
|
+
|
|
71
|
+
@errors << I18n.t('hyrax.flexible_schema_validators.redirects_validator.errors.invalid_available_on')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Class names declared in this m3 profile's top-level `classes:` block,
|
|
75
|
+
# filtered to keep only those that represent works or collections.
|
|
76
|
+
# FileSets, AdminSets, and any non-work/non-collection class are
|
|
77
|
+
# excluded — redirects only apply to works and collections.
|
|
78
|
+
def profile_work_or_collection_classes
|
|
79
|
+
@profile_work_or_collection_classes ||= begin
|
|
80
|
+
declared = clean(Array(@profile&.dig('classes')&.keys))
|
|
81
|
+
declared.select { |name| work_or_collection?(name) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def work_or_collection?(class_name)
|
|
86
|
+
registered_collection_names.include?(class_name) ||
|
|
87
|
+
registered_work_names.include?(class_name)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def registered_collection_names
|
|
91
|
+
@registered_collection_names ||= clean(Hyrax::ModelRegistry.collection_class_names)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Work class names from the registry, with collection / file_set /
|
|
95
|
+
# admin_set names explicitly excluded. The registry can include any
|
|
96
|
+
# class an adopter has registered as a curation concern, so the
|
|
97
|
+
# exclusion guards against e.g. a FileSet being registered alongside
|
|
98
|
+
# works and slipping through as a "work" type for redirects.
|
|
99
|
+
# Each registered name is also paired with its `Resource`-suffixed
|
|
100
|
+
# Valkyrie equivalent — `class_validator` accepts both forms.
|
|
101
|
+
def registered_work_names
|
|
102
|
+
@registered_work_names ||= begin
|
|
103
|
+
works = clean(Hyrax::ModelRegistry.work_class_names)
|
|
104
|
+
works -= clean(Hyrax::ModelRegistry.collection_class_names)
|
|
105
|
+
works -= clean(Hyrax::ModelRegistry.file_set_class_names)
|
|
106
|
+
works -= clean(Hyrax::ModelRegistry.admin_set_class_names)
|
|
107
|
+
works.flat_map { |name| [name, "#{name}Resource"] }
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def clean(names)
|
|
112
|
+
names.map { |name| name.to_s.delete_prefix('::') }
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
# Handles JSON schema validation for flexible metadata profiles
|
|
6
|
+
class SchemaValidator
|
|
7
|
+
def initialize(schemer, profile, errors)
|
|
8
|
+
@schemer = schemer
|
|
9
|
+
@profile = profile
|
|
10
|
+
@errors = errors
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def validate!
|
|
14
|
+
@schemer.validate(@profile).to_a&.each do |error|
|
|
15
|
+
pointer = error['data_pointer']
|
|
16
|
+
type = error['type']
|
|
17
|
+
|
|
18
|
+
if pointer.end_with?('/available_on') && error['data'].nil? && type == 'object'
|
|
19
|
+
@errors << "Schema error at `#{pointer}`: `available_on` cannot be empty and must have a `class` or `context` sub-property."
|
|
20
|
+
elsif type == 'required'
|
|
21
|
+
missing_keys = error.dig('details', 'missing_keys')&.join("', '")
|
|
22
|
+
@errors << "Schema error at `#{pointer}`: Missing required properties: '#{missing_keys}'."
|
|
23
|
+
else
|
|
24
|
+
@errors << "Schema error at `#{pointer}`: Invalid value `#{error['data'].inspect}` for type `#{type}`."
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :schemer, :profile, :errors
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaValidators
|
|
5
|
+
class SortPropertiesValidator
|
|
6
|
+
attr_reader :profile, :sort_properties
|
|
7
|
+
|
|
8
|
+
def initialize(profile, warnings)
|
|
9
|
+
@profile = profile
|
|
10
|
+
@warnings = warnings
|
|
11
|
+
@sort_properties = find_sort_properties
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def validate!
|
|
15
|
+
sort_properties.each do |property|
|
|
16
|
+
properties_without_sort_properties = work_types_from_profile - (profile.dig('properties', property, 'available_on', 'class') || [])
|
|
17
|
+
next if properties_without_sort_properties.empty?
|
|
18
|
+
|
|
19
|
+
msg = I18n.t(
|
|
20
|
+
'hyrax.flexible_schema_validators.sort_properties_validator.warnings.message',
|
|
21
|
+
property: property,
|
|
22
|
+
classes: properties_without_sort_properties.join(', ')
|
|
23
|
+
)
|
|
24
|
+
@warnings << msg
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def find_sort_properties
|
|
31
|
+
CatalogController.blacklight_config.sort_fields.keys.filter_map do |sort_key|
|
|
32
|
+
field = sort_key.split.first.sub(/_[^_]*$/, '')
|
|
33
|
+
field unless system_properties.include?(field)
|
|
34
|
+
end.uniq
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def system_properties
|
|
38
|
+
%w[score system_modified system_create]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def work_types_from_profile
|
|
42
|
+
work_types = available_works.map do |work_type|
|
|
43
|
+
Valkyrie.config.resource_class_resolver.call(work_type).to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
profile['classes'].keys.filter_map { |klass_name| klass_name if work_types.include?(klass_name) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def available_works
|
|
50
|
+
Hyrax.config.registered_curation_concern_types
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -52,6 +52,8 @@ module Hyrax
|
|
|
52
52
|
|
|
53
53
|
##
|
|
54
54
|
# Re-index the resource.
|
|
55
|
+
# If the updated object is a file set used as the thumbnail of a parent work,
|
|
56
|
+
# also reindex that parent so thumbnail_alt_text_tesim stays fresh.
|
|
55
57
|
#
|
|
56
58
|
# Called when 'object.metadata.updated' event is published
|
|
57
59
|
# @param [Dry::Events::Event] event
|
|
@@ -59,6 +61,7 @@ module Hyrax
|
|
|
59
61
|
def on_object_metadata_updated(event)
|
|
60
62
|
return unless resource? event[:object]
|
|
61
63
|
Hyrax.index_adapter.save(resource: event[:object])
|
|
64
|
+
reindex_parent_for_thumbnail(event[:object]) if event[:object].file_set?
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
##
|
|
@@ -96,6 +99,14 @@ module Hyrax
|
|
|
96
99
|
|
|
97
100
|
private
|
|
98
101
|
|
|
102
|
+
def reindex_parent_for_thumbnail(file_set)
|
|
103
|
+
parent = Hyrax.custom_queries.find_parent_work(resource: file_set)
|
|
104
|
+
return unless parent&.thumbnail_id == file_set.id
|
|
105
|
+
Hyrax.index_adapter.save(resource: parent)
|
|
106
|
+
rescue Valkyrie::Persistence::ObjectNotFoundError, Hyrax::ObjectNotFoundError
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
99
110
|
def resource?(resource)
|
|
100
111
|
return true if resource.is_a? Valkyrie::Resource
|
|
101
112
|
log_non_resource(resource)
|