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
|
@@ -2,6 +2,28 @@ $drawer-small: 40px;
|
|
|
2
2
|
$drawer-large: 260px;
|
|
3
3
|
$gutter-width: $grid-gutter-width/2;
|
|
4
4
|
|
|
5
|
+
// Backdrop overlay for mobile sidebar - automatically shows when sidebar is maximized
|
|
6
|
+
.sidebar-backdrop {
|
|
7
|
+
display: none;
|
|
8
|
+
position: fixed;
|
|
9
|
+
top: 0;
|
|
10
|
+
left: 0;
|
|
11
|
+
right: 0;
|
|
12
|
+
bottom: 0;
|
|
13
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
14
|
+
z-index: 1000;
|
|
15
|
+
opacity: 0;
|
|
16
|
+
transition: opacity 0.3s ease;
|
|
17
|
+
|
|
18
|
+
@media screen and (max-width: 991px) {
|
|
19
|
+
// Automatically show when sidebar is maximized preventing flash on page load
|
|
20
|
+
.sidebar.maximized.js-initialized ~ & {
|
|
21
|
+
display: block;
|
|
22
|
+
opacity: 1;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
5
27
|
.main-content {
|
|
6
28
|
padding-left: $drawer-small + $gutter-width;
|
|
7
29
|
padding-right: $gutter-width;
|
|
@@ -9,10 +31,29 @@ $gutter-width: $grid-gutter-width/2;
|
|
|
9
31
|
background-color: $admin-content-background-color;
|
|
10
32
|
position: absolute;
|
|
11
33
|
width: 100%;
|
|
34
|
+
transition: opacity 0.3s ease;
|
|
12
35
|
|
|
13
36
|
&.maximized {
|
|
14
37
|
padding-left: $drawer-large + $gutter-width;
|
|
15
38
|
}
|
|
39
|
+
|
|
40
|
+
// On mobile, sidebar overlays content instead of pushing it
|
|
41
|
+
@media screen and (max-width: 991px) {
|
|
42
|
+
padding-left: $drawer-small + $gutter-width;
|
|
43
|
+
// Keep padding the same even when sidebar is maximized
|
|
44
|
+
// Only grey out after JS has initialized preventing flash on page load
|
|
45
|
+
&.maximized:not(.js-initialized) {
|
|
46
|
+
padding-left: $drawer-small + $gutter-width;
|
|
47
|
+
opacity: 1;
|
|
48
|
+
pointer-events: auto;
|
|
49
|
+
}
|
|
50
|
+
&.maximized.js-initialized {
|
|
51
|
+
padding-left: $drawer-small + $gutter-width;
|
|
52
|
+
// Grey out and disable content when sidebar is open
|
|
53
|
+
opacity: 0.5;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
16
57
|
}
|
|
17
58
|
|
|
18
59
|
// .sidebar is a class on the div
|
|
@@ -25,6 +66,40 @@ $gutter-width: $grid-gutter-width/2;
|
|
|
25
66
|
width: $drawer-small;
|
|
26
67
|
z-index: 1000;
|
|
27
68
|
|
|
69
|
+
// On mobile sidebar overlays content when maximized
|
|
70
|
+
@media screen and (max-width: 991px) {
|
|
71
|
+
width: $drawer-small;
|
|
72
|
+
|
|
73
|
+
// Force sidebar to start collapsed on mobile preventing flash of open sidebar on page load
|
|
74
|
+
&:not(.js-initialized).maximized {
|
|
75
|
+
width: $drawer-small !important;
|
|
76
|
+
|
|
77
|
+
// Hide maximized content initially on mobile
|
|
78
|
+
.sidebar-action-text,
|
|
79
|
+
a span + span,
|
|
80
|
+
h5 {
|
|
81
|
+
display: none !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.h5,
|
|
85
|
+
.profile,
|
|
86
|
+
.collapse-toggle::after {
|
|
87
|
+
opacity: 0 !important;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.sidebar-toggle {
|
|
91
|
+
transform: none !important;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&.maximized.js-initialized {
|
|
96
|
+
position: fixed;
|
|
97
|
+
z-index: 1001;
|
|
98
|
+
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
|
|
99
|
+
width: $drawer-large;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
28
103
|
&.maximized {
|
|
29
104
|
width: $drawer-large;
|
|
30
105
|
|
|
@@ -83,12 +158,32 @@ $gutter-width: $grid-gutter-width/2;
|
|
|
83
158
|
cursor: pointer;
|
|
84
159
|
background-color: $body-background-color;
|
|
85
160
|
border-radius: 50%;
|
|
86
|
-
|
|
161
|
+
border: none;
|
|
162
|
+
padding: 0;
|
|
163
|
+
line-height: 24px;
|
|
87
164
|
position: absolute;
|
|
88
|
-
right: -
|
|
165
|
+
right: -12px;
|
|
89
166
|
text-align: center;
|
|
90
|
-
width:
|
|
167
|
+
width: 24px;
|
|
168
|
+
height: 24px;
|
|
169
|
+
min-width: 24px;
|
|
170
|
+
min-height: 24px;
|
|
91
171
|
z-index: 1001;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
|
|
176
|
+
// Focus styles for keyboard navigation
|
|
177
|
+
&:focus {
|
|
178
|
+
outline: 2px solid #005fcc;
|
|
179
|
+
outline-offset: 2px;
|
|
180
|
+
box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #005fcc;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Centered icon
|
|
184
|
+
.fa {
|
|
185
|
+
display: block;
|
|
186
|
+
}
|
|
92
187
|
}
|
|
93
188
|
|
|
94
189
|
a {
|
|
@@ -7,10 +7,7 @@ module Qa::Authorities
|
|
|
7
7
|
def search(_q, controller)
|
|
8
8
|
# The Hyrax::CollectionSearchBuilder expects a current_user
|
|
9
9
|
return [] unless controller.current_user
|
|
10
|
-
|
|
11
|
-
docs = response.documents
|
|
12
|
-
|
|
13
|
-
docs.map do |doc|
|
|
10
|
+
search_documents(controller).map do |doc|
|
|
14
11
|
{ id: doc.id, label: doc.title, value: doc.id }
|
|
15
12
|
end
|
|
16
13
|
end
|
|
@@ -27,13 +24,16 @@ module Qa::Authorities
|
|
|
27
24
|
)
|
|
28
25
|
end
|
|
29
26
|
|
|
30
|
-
def
|
|
27
|
+
def search_documents(controller)
|
|
31
28
|
access = controller.params[:access] || 'read'
|
|
29
|
+
builder = search_service(controller).search_builder
|
|
30
|
+
.with(q: controller.params[:q])
|
|
31
|
+
.with_access(access)
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
Hyrax::SolrService.fetch_all do |rows, start|
|
|
34
|
+
controller.blacklight_config.repository.search(
|
|
35
|
+
builder.query.merge(rows: rows, start: start, fl: 'id,title_tesim,has_model_ssim')
|
|
36
|
+
)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'google/cloud/errors'
|
|
3
|
+
|
|
4
|
+
module Hyrax
|
|
5
|
+
module AnalyticsErrorHandling
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
rescue_from Google::Cloud::PermissionDeniedError, with: :handle_analytics_permission_error
|
|
10
|
+
rescue_from Google::Cloud::Error, with: :handle_analytics_general_error
|
|
11
|
+
rescue_from StandardError, with: :handle_analytics_general_error
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def handle_analytics_permission_error(exception)
|
|
17
|
+
Rails.logger.error "Analytics permission error: #{exception.message}"
|
|
18
|
+
@analytics_error = {
|
|
19
|
+
type: 'permission',
|
|
20
|
+
title: I18n.t('hyrax.admin.analytics.errors.permission.title'),
|
|
21
|
+
message: I18n.t('hyrax.admin.analytics.errors.permission.message'),
|
|
22
|
+
details: exception.message,
|
|
23
|
+
troubleshooting_steps: Array.wrap(I18n.t('hyrax.admin.analytics.errors.permission.troubleshooting_steps')),
|
|
24
|
+
documentation_url: I18n.t('hyrax.admin.analytics.errors.permission.documentation_url')
|
|
25
|
+
}
|
|
26
|
+
set_empty_analytics_data
|
|
27
|
+
render_analytics_with_error
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handle_analytics_general_error(exception)
|
|
31
|
+
raise exception unless analytics_related_error?(exception)
|
|
32
|
+
|
|
33
|
+
Rails.logger.error "Analytics error: #{exception.message}"
|
|
34
|
+
|
|
35
|
+
error_type = determine_error_type(exception)
|
|
36
|
+
|
|
37
|
+
@analytics_error = {
|
|
38
|
+
type: error_type,
|
|
39
|
+
title: I18n.t("hyrax.admin.analytics.errors.#{error_type}.title"),
|
|
40
|
+
message: I18n.t("hyrax.admin.analytics.errors.#{error_type}.message"),
|
|
41
|
+
details: exception.message,
|
|
42
|
+
troubleshooting_steps: Array.wrap(I18n.t("hyrax.admin.analytics.errors.#{error_type}.troubleshooting_steps")),
|
|
43
|
+
documentation_url: I18n.t("hyrax.admin.analytics.errors.#{error_type}.documentation_url")
|
|
44
|
+
}
|
|
45
|
+
set_empty_analytics_data
|
|
46
|
+
render_analytics_with_error
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def determine_error_type(exception)
|
|
50
|
+
case exception.message
|
|
51
|
+
when /property.*not found/i, /invalid property/i
|
|
52
|
+
'invalid_property'
|
|
53
|
+
when /authentication/i, /credentials/i, /unauthorized/i
|
|
54
|
+
'authentication'
|
|
55
|
+
when /quota/i, /rate limit/i
|
|
56
|
+
'quota_exceeded'
|
|
57
|
+
else
|
|
58
|
+
'general'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def analytics_related_error?(exception)
|
|
63
|
+
return true if exception.is_a?(Google::Cloud::Error)
|
|
64
|
+
exception.message.include?('analytics') ||
|
|
65
|
+
exception.message.include?('Google') ||
|
|
66
|
+
exception.message.include?('property') ||
|
|
67
|
+
exception.backtrace&.any? { |line| line.include?('analytics') || line.include?('google') }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def set_empty_analytics_data
|
|
71
|
+
# Set empty data structures to prevent view errors
|
|
72
|
+
empty_data = { pageviews: [], work_page_views: [], downloads: [], all_top_collections: [],
|
|
73
|
+
top_collections: [], top_downloads: [], top_collection_pages: [], accessible_works: [],
|
|
74
|
+
accessible_file_sets: [], works_count: 0, top_works: [], top_file_set_downloads: [],
|
|
75
|
+
uniques: [], files: [] }
|
|
76
|
+
|
|
77
|
+
empty_data.each { |key, value| instance_variable_set("@#{key}", value) if instance_variable_get("@#{key}").nil? }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def render_analytics_with_error
|
|
81
|
+
respond_to do |format|
|
|
82
|
+
format.html { render :index }
|
|
83
|
+
format.csv { render plain: "Analytics data unavailable due to configuration error", status: :service_unavailable }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def safe_analytics_call(method_name, *args)
|
|
88
|
+
Hyrax::Analytics.send(method_name, *args)
|
|
89
|
+
rescue Google::Cloud::PermissionDeniedError, Google::Cloud::Error => e
|
|
90
|
+
Rails.logger.warn "Analytics call failed: #{method_name} - #{e.message}"
|
|
91
|
+
[]
|
|
92
|
+
rescue StandardError => e
|
|
93
|
+
Rails.logger.warn "Unexpected analytics error: #{method_name} - #{e.message}"
|
|
94
|
+
[]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -3,7 +3,9 @@ module Hyrax
|
|
|
3
3
|
module CollectionsControllerBehavior
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
include Blacklight::AccessControls::Catalog
|
|
6
|
-
include Blacklight::
|
|
6
|
+
include Blacklight::Configurable
|
|
7
|
+
include Blacklight::SearchContext
|
|
8
|
+
include Hyrax::RedirectToDisplayUrl
|
|
7
9
|
|
|
8
10
|
included do
|
|
9
11
|
# include the display_trophy_link view helper method
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
##
|
|
5
|
+
# A shared module for controllers to ensure that a resource has been fully
|
|
6
|
+
# migrated from a Wings-backed ActiveFedora object to a native Valkyrie resource
|
|
7
|
+
# before an action (like `edit`) is performed.
|
|
8
|
+
#
|
|
9
|
+
# This is a temporary solution to handle just-in-time migrations for legacy
|
|
10
|
+
# objects when `Hyrax.config.flexible?` is true.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# class MyController < ApplicationController
|
|
14
|
+
# include Hyrax::EnsureMigratedBehavior
|
|
15
|
+
#
|
|
16
|
+
# before_action do
|
|
17
|
+
# @resource = find_my_resource
|
|
18
|
+
# @resource = ensure_migrated(resource: @resource, form: build_form, transaction_key: 'my.transaction')
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
module EnsureMigratedBehavior
|
|
22
|
+
extend ActiveSupport::Concern
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# @param resource [Valkyrie::Resource] the resource to check
|
|
28
|
+
# @param transaction_key [String] the key for the update transaction
|
|
29
|
+
#
|
|
30
|
+
# @return [Valkyrie::Resource] the migrated resource if migration was needed,
|
|
31
|
+
# otherwise the original resource.
|
|
32
|
+
def ensure_migrated(resource:, transaction_key:)
|
|
33
|
+
return resource unless resource.flexible? && wings_backed?(resource)
|
|
34
|
+
|
|
35
|
+
# Create a minimal form object to run the transaction.
|
|
36
|
+
# We can't use the controller's form because it may fail to build
|
|
37
|
+
# for a Wings-backed object, creating a circular dependency.
|
|
38
|
+
form = Hyrax::Forms::ResourceForm.for(resource: resource)
|
|
39
|
+
result = transactions[transaction_key].call(form)
|
|
40
|
+
|
|
41
|
+
raise "Valkyrie lazy migration failed for #{resource.class} #{resource.id}: #{result.failure}" unless result.success?
|
|
42
|
+
|
|
43
|
+
result.value!
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def wings_backed?(resource)
|
|
47
|
+
resource.respond_to?(:wings?) && resource.wings?
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleCatalogBehavior
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
class_methods do
|
|
8
|
+
def load_flexible_schema
|
|
9
|
+
previous_profile, current_profile = Hyrax::FlexibleSchema.order("created_at asc").last(2).map(&:profile)
|
|
10
|
+
return if previous_profile.blank? && current_profile.blank?
|
|
11
|
+
|
|
12
|
+
current_profile = previous_profile if current_profile.nil?
|
|
13
|
+
remove_old_properties!(previous_profile['properties'], current_profile['properties'].keys) if current_profile != previous_profile
|
|
14
|
+
properties_hash = current_profile['properties']
|
|
15
|
+
properties_hash.each do |itemprop, prop|
|
|
16
|
+
label = display_label_for(itemprop, prop)
|
|
17
|
+
|
|
18
|
+
view_options = prop['view']
|
|
19
|
+
indexing = prop['indexing']
|
|
20
|
+
next if indexing.nil?
|
|
21
|
+
|
|
22
|
+
# prevents all restricted fields from being added to blacklight config
|
|
23
|
+
# to prevent them from being exposed in catalog search results.
|
|
24
|
+
# They remain available on show pages, based on visibility.
|
|
25
|
+
if restricted_field?(indexing)
|
|
26
|
+
remove_from_blacklight_config!(itemprop, indexing)
|
|
27
|
+
next
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# `view.search_results: false` in the m3 profile hides this property from catalog
|
|
31
|
+
# search-result columns. Only gates the dynamic add_index_field path below;
|
|
32
|
+
# properties already declared in CatalogController are left untouched, and
|
|
33
|
+
# the `qf` (query-field relevance) list is unaffected. Facet registration below
|
|
34
|
+
# is intentionally not gated — a hidden property can still be facetable.
|
|
35
|
+
if catalog_indexable?(view_options) && stored_searchable?(indexing, itemprop)
|
|
36
|
+
index_args = { itemprop:, label: }
|
|
37
|
+
|
|
38
|
+
if facetable?(indexing, itemprop)
|
|
39
|
+
index_args[:link_to_facet] = "#{itemprop}_sim"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
name = blacklight_config.index_fields.keys.detect { |key| key.start_with?(itemprop) }
|
|
43
|
+
name ||= "#{itemprop}_tesim"
|
|
44
|
+
|
|
45
|
+
# for properties that DO exist in the CatalogController
|
|
46
|
+
if blacklight_config.index_fields[name].present?
|
|
47
|
+
if label
|
|
48
|
+
blacklight_config.index_fields[name].label = label
|
|
49
|
+
blacklight_config.index_fields[name].custom_label = true
|
|
50
|
+
end
|
|
51
|
+
blacklight_config.index_fields[name].itemprop = itemprop
|
|
52
|
+
|
|
53
|
+
blacklight_config.index_fields[name].link_to_facet = index_args[:link_to_facet]
|
|
54
|
+
|
|
55
|
+
if require_view_helper_method?(view_options)
|
|
56
|
+
# add or update the helper method so linked fields will render correctly in the index view
|
|
57
|
+
blacklight_config.index_fields[name].helper_method = view_option_for_helper_method(view_options)
|
|
58
|
+
# the helper method for index_field_link needs the field name
|
|
59
|
+
blacklight_config.index_fields[name].field_name = itemprop
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
# for properties that DO NOT exist in the catalog controller
|
|
63
|
+
if require_view_helper_method?(view_options)
|
|
64
|
+
# add the view helper method to the arguments hash when creating a property
|
|
65
|
+
index_args[:helper_method] = view_option_for_helper_method(view_options)
|
|
66
|
+
# the helper method for index_field_link needs the field name
|
|
67
|
+
index_args[:field_name] = itemprop
|
|
68
|
+
end
|
|
69
|
+
# if a property in the metadata profile doesn't exist in the CatalogController, add it
|
|
70
|
+
blacklight_config.add_index_field(name, index_args)
|
|
71
|
+
|
|
72
|
+
# all index fields get this property so an admin can hide a property from the catalog search results
|
|
73
|
+
# by adding the name of the property via admin dashboard > Settings > Accounts > Hidden index fields
|
|
74
|
+
# NOTE: it is likely this will be handled by the metadata profile in the future
|
|
75
|
+
blacklight_config.index_fields[name].if = :render_optionally?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
qf = blacklight_config.search_fields['all_fields'].solr_parameters[:qf]
|
|
79
|
+
unless qf.include?(name)
|
|
80
|
+
qf << " #{name}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if facetable?(indexing, itemprop)
|
|
85
|
+
name = "#{itemprop}_sim"
|
|
86
|
+
unless blacklight_config.facet_fields[name].present?
|
|
87
|
+
blacklight_config.add_facet_field(name, label: label)
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
# if the property does not have facetable in the indexing section of the metadata profile, remove the facet field from the blacklight config
|
|
91
|
+
name = "#{itemprop}_sim"
|
|
92
|
+
blacklight_config.facet_fields.delete(name)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
# Returns true if the view options require a helper method to render the linked field correctly in the index view
|
|
100
|
+
# @param view_options [Hash] the view options ex: {"render_as"=>"linked", "html_dl"=>true}
|
|
101
|
+
# @return [Boolean] to determine if the view_option_for_helper_method should be called
|
|
102
|
+
def require_view_helper_method?(view_options)
|
|
103
|
+
view_options.present? && %w[external_link linked rights_statement].include?(view_options.dig('render_as'))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Returns the helper method that will render the linked field correctly in the index view
|
|
107
|
+
# @param view_options [Hash] the view options ex: {"render_as"=>"linked", "html_dl"=>true}
|
|
108
|
+
# @return [Symbol] helper method from Hyrax::HyraxHelperBehavior
|
|
109
|
+
def view_option_for_helper_method(view_options)
|
|
110
|
+
render_as = view_options.dig('render_as')
|
|
111
|
+
return :iconify_auto_link if render_as == 'external_link'
|
|
112
|
+
return :index_field_link if render_as == 'linked'
|
|
113
|
+
return :rights_statement_links if render_as == 'rights_statement'
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def display_label_for(field_name, config)
|
|
117
|
+
display_label = config.fetch('display_label', {})&.with_indifferent_access || {}
|
|
118
|
+
display_label = { default: display_label } if display_label.is_a?(String)
|
|
119
|
+
display_label[:default] = field_name.to_s.humanize if display_label[:default].blank?
|
|
120
|
+
# Return a lambda so locale and translation are resolved at render time,
|
|
121
|
+
# not at initialize time (before before_action :set_locale runs).
|
|
122
|
+
lambda { |*|
|
|
123
|
+
label = display_label[I18n.locale] || display_label[:default]
|
|
124
|
+
I18n.t(label, default: label)
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def stored_searchable?(indexing, itemprop)
|
|
129
|
+
indexing.include?('stored_searchable') || indexing.include?("#{itemprop}_tesim")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# True when the property declares `admin_only` or `editor_only` in its
|
|
133
|
+
# indexing array. Restricted fields are never exposed through the
|
|
134
|
+
# Blacklight catalog (no index column, no facet, no free-text match);
|
|
135
|
+
# visibility is enforced on show pages by the `field_visible?` view
|
|
136
|
+
# helper.
|
|
137
|
+
def restricted_field?(indexing)
|
|
138
|
+
indexing.include?("admin_only") || indexing.include?("editor_only")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Returns false only when the m3 profile sets `view.search_results: false`
|
|
142
|
+
# for the property; absent or `true` keeps existing catalog-display behavior.
|
|
143
|
+
def catalog_indexable?(view_options)
|
|
144
|
+
return true unless view_options.is_a?(Hash)
|
|
145
|
+
view_options['search_results'] != false
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def facetable?(indexing, itemprop)
|
|
149
|
+
indexing.include?('facetable')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def remove_old_properties!(previous_profile_properties, current_property_keys)
|
|
153
|
+
props = previous_profile_properties.keys - current_property_keys
|
|
154
|
+
props.each do |prop|
|
|
155
|
+
indexing = previous_profile_properties.dig(prop, 'indexing')
|
|
156
|
+
remove_from_blacklight_config!(prop, indexing)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Evict every Blacklight registration for `itemprop`. Collects the set of
|
|
161
|
+
# Solr field names to remove from three sources:
|
|
162
|
+
# - "<itemprop>_tesim" — the default Solr field name used as the
|
|
163
|
+
# index field for this property,
|
|
164
|
+
# - "<itemprop>_sim" — the default Solr field name used as the
|
|
165
|
+
# facet field for this property,
|
|
166
|
+
# - any additional Solr-field names explicitly declared in `indexing:`
|
|
167
|
+
# (filtering out the directive flags `stored_searchable`, `facetable`,
|
|
168
|
+
# `admin_only`, and `editor_only`).
|
|
169
|
+
# Then removes those exact names from `facet_fields`, `index_fields`, and
|
|
170
|
+
# the all_fields qf. Exact-name matching avoids prefix collisions where
|
|
171
|
+
# e.g. `title` would otherwise match `title_alternative_*`.
|
|
172
|
+
INDEXING_DIRECTIVES = %w[stored_searchable facetable admin_only editor_only].freeze
|
|
173
|
+
|
|
174
|
+
def remove_from_blacklight_config!(itemprop, indexing = nil)
|
|
175
|
+
names = solr_field_names_for(itemprop, indexing)
|
|
176
|
+
names.each do |name|
|
|
177
|
+
blacklight_config.facet_fields.delete(name)
|
|
178
|
+
blacklight_config.index_fields.delete(name)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
qf = blacklight_config.search_fields['all_fields']&.solr_parameters&.dig(:qf)
|
|
182
|
+
return if qf.nil?
|
|
183
|
+
names.each do |name|
|
|
184
|
+
qf.slice!(" #{name}")
|
|
185
|
+
qf.slice!(name)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def solr_field_names_for(itemprop, indexing)
|
|
190
|
+
default_fields = ["#{itemprop}_tesim", "#{itemprop}_sim"]
|
|
191
|
+
declared_fields = (indexing || []) - INDEXING_DIRECTIVES
|
|
192
|
+
(default_fields + declared_fields).uniq
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def initialize
|
|
197
|
+
self.class.load_flexible_schema
|
|
198
|
+
super
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Hook to allow optional rendering at the app level
|
|
202
|
+
def render_optionally?
|
|
203
|
+
true
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
module FlexibleSchemaBehavior
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
before_action :set_latest_schema_version, only: [:new, :edit]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def set_latest_schema_version
|
|
14
|
+
@latest_schema_version = Hyrax::FlexibleSchema.current_schema_id.to_f
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hyrax
|
|
4
|
+
# Controller concern that sends visitors who land on a path with a
|
|
5
|
+
# redirect-table row pointing elsewhere to that other path. Included on
|
|
6
|
+
# work and collection show controllers via the curation-concerns
|
|
7
|
+
# behavior modules.
|
|
8
|
+
#
|
|
9
|
+
# Two request shapes hit this concern:
|
|
10
|
+
#
|
|
11
|
+
# - Direct UUID URL visits (`/concern/generic_works/<uuid>`) — Rails
|
|
12
|
+
# routes natively to the show action. If the resource has a display
|
|
13
|
+
# alias, the row keyed on the UUID URL has `to_path` pointing at the
|
|
14
|
+
# alias, and the before_action 301s the visitor there.
|
|
15
|
+
# - In-process dispatches from `Hyrax::RedirectsController` — the
|
|
16
|
+
# resolver finds a display-URL row and re-dispatches the request
|
|
17
|
+
# through `recognize_path` + `controller.dispatch`. To avoid the
|
|
18
|
+
# before_action firing again on the same logical request, the
|
|
19
|
+
# resolver sets `request.env['hyrax.redirects.dispatched'] = true`
|
|
20
|
+
# before dispatching; this concern checks the same env key and
|
|
21
|
+
# no-ops when set.
|
|
22
|
+
#
|
|
23
|
+
# See documentation/redirects.md.
|
|
24
|
+
module RedirectToDisplayUrl
|
|
25
|
+
extend ActiveSupport::Concern
|
|
26
|
+
|
|
27
|
+
included do
|
|
28
|
+
before_action :redirect_to_display_url_if_needed, only: :show
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def redirect_to_display_url_if_needed
|
|
34
|
+
return if request.env['hyrax.redirects.dispatched']
|
|
35
|
+
return unless Hyrax.config.redirects_active?
|
|
36
|
+
row = Hyrax::RedirectsLookup.find_row(request.path)
|
|
37
|
+
return if row.blank?
|
|
38
|
+
return if row.to_path == request.path
|
|
39
|
+
redirect_to with_locale(row.to_path), status: :moved_permanently
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Carry the visitor's requested locale (set by Hyrax::Controller#set_locale
|
|
43
|
+
# from `params[:locale]`) across the 301 so the destination page renders in
|
|
44
|
+
# the same language. Appended as `?locale=<value>` so this works whether the
|
|
45
|
+
# host app uses path-prefix or query-string locales. The locale value is
|
|
46
|
+
# URL-encoded via Rack::Utils.build_query so attacker-controlled chars in
|
|
47
|
+
# params[:locale] can't inject extra query params into the Location header.
|
|
48
|
+
def with_locale(path)
|
|
49
|
+
return path if params[:locale].blank?
|
|
50
|
+
separator = path.include?('?') ? '&' : '?'
|
|
51
|
+
"#{path}#{separator}#{Rack::Utils.build_query(locale: params[:locale])}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|