diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f08b5735..21ed03a19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: samvera: samvera/circleci-orb@1 - browser-tools: circleci/browser-tools@1.3 + browser-tools: circleci/browser-tools@1.4.6 ruby: circleci/ruby@2 node: circleci/node@5 @@ -10,13 +10,13 @@ jobs: parameters: ruby_version: type: string - default: 2.7.8 + default: 3.2.2 bundler_version: type: string default: 2.4.8 rails_version: type: string - default: '5.1.6' + default: '6.1.7.6' solr_config_path: type: string fcrepo_version: @@ -61,6 +61,7 @@ jobs: BUNDLE_PATH: vendor/bundle BUNDLE_JOBS: 4 BUNDLE_RETRY: 3 + HYKU_CACHE_ROOT: /tmp/hyku-cache HYKU_RESTRICT_CREATE_AND_DESTROY_PERMISSIONS: 'true' SOLR_ADMIN_USER: admin SOLR_ADMIN_PASSWORD: admin @@ -79,7 +80,9 @@ jobs: ruby_version: << parameters.ruby_version >> bundler_version: << parameters.bundler_version >> - samvera/rubocop - - browser-tools/install-chrome + - browser-tools/install-chrome: + chrome-version: 114.0.5735.90 # see https://github.com/CircleCI-Public/browser-tools-orb/pull/96 + replace-existing: true - browser-tools/install-chromedriver - run: name: Check Chrome install @@ -95,6 +98,6 @@ workflows: ci: jobs: - bundle: - ruby_version: "2.7.8" - name: "ruby2-7-8" + ruby_version: "3.2.2" + name: "ruby3-2-2" solr_config_path: 'solr/conf' diff --git a/.dockerignore b/.dockerignore index 45c1f98e1..e07a10c04 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,7 +4,6 @@ ./coverage ./docker ./fcrepo -./importer ./log ./pg ./public/assets diff --git a/.env b/.env index d915fdd7a..540f0aacf 100644 --- a/.env +++ b/.env @@ -1,5 +1,6 @@ CHROME_HOSTNAME=chrome COMPOSE_DOCKER_CLI_BUILD=1 +DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL=true DB_ADAPTER=postgresql DB_HOST=db DB_HOST=db @@ -13,18 +14,19 @@ FCREPO_BASE_PATH=/hykudemo FCREPO_HOST=fcrepo FCREPO_PORT=8080 FCREPO_REST_PATH=rest +HYRAX_ACTIVE_JOB_QUEUE=good_job +HYRAX_FITS_PATH=/app/fits/fits.sh INITIAL_ADMIN_EMAIL=admin@example.com INITIAL_ADMIN_PASSWORD=testing123 -JAVA_OPTS=-Xmx4g -Xms1g IN_DOCKER=true +JAVA_OPTS= +JAVA_OPTS=-Xmx4g -Xms1g LD_LIBRARY_PATH=/opt/fits/tools/mediainfo/linux +NEGATIVE_CAPTCHA_SECRET=default-value-change-me PASSENGER_APP_ENV=development RAILS_LOG_TO_STDOUT=true REDIS_HOST=redis SECRET_KEY_BASE=asdf -HYRAX_ACTIVE_JOB_QUEUE=sidekiq -HYRAX_FITS_PATH=/app/fits/fits.sh -NEGATIVE_CAPTCHA_SECRET=default-value-change-me SOLR_ADMIN_PASSWORD=SolrRocks SOLR_ADMIN_USER=solr SOLR_COLLECTION_NAME=hydra-development @@ -32,6 +34,8 @@ SOLR_CONFIGSET_NAME=hyku SOLR_HOST=solr SOLR_PORT=8983 SOLR_URL=http://solr:SolrRocks@solr:8983/solr/ +TB_RSPEC_FORMATTER=progress +TB_RSPEC_OPTIONS="--format RspecJunitFormatter --out rspec.xml" # Comment out these 5 for single tenancy / Uncomment for multi HYKU_ADMIN_HOST=hyku.test diff --git a/.rubocop.yml b/.rubocop.yml index 90961c959..fc1044e12 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,129 +1,147 @@ -# Turn on RSpec cops -require: rubocop-rspec -inherit_from: .rubocop_todo.yml +inherit_from: + - .rubocop_fixme.yml -# With the rubocop 0.47.0 and rubocop-rspec 1.8.0 the following stderr message was sent: -# An error occurred while RSpec/DescribedClass cop was inspecting path/to/file -RSpec/DescribedClass: - Enabled: false +inherit_gem: + bixby: bixby_default.yml AllCops: + NewCops: disable + TargetRubyVersion: 3.2.2 DisplayCopNames: true - TargetRubyVersion: 2.3 Exclude: - - 'bin/**/*' - 'db/**/*' - - 'config/**/*' - - 'vendor/**/*' - - '.internal_test_app/**/*' - - 'spec/fixtures/**/*' - - 'spec/internal/**/*' + - 'script/**/*' - 'spec/test_app_templates/**/*' - - 'Rakefile' - - 'lib/tasks/rubocop.rake' - # disabling collections controller as most of the rubocop errors are in hyrax - - 'app/controllers/hyrax/dashboard/collections_controller.rb' - -Rails: - Enabled: true + - 'vendor/**/*' + - 'lib/hyrax/specs/**/*' + - 'bin/graph' + - 'bin/import_from_purl' -Rails/DynamicFindBy: - Whitelist: - - find_by_user_key +Lint/ImplicitStringConcatenation: Exclude: - - 'lib/importer/factory/object_factory.rb' + - 'lib/generators/hyrax/**/*' -Rails/UnknownEnv: - Environments: - - development - - production - - staging - - test +Rails/Output: + Exclude: + - 'lib/generators/**/*' -Metrics/LineLength: - Max: 120 +Metrics/BlockLength: + IgnoredMethods: ['included'] Exclude: - - 'app/controllers/catalog_controller.rb' - - 'spec/controllers/curation_concerns/generic_works_controller_spec.rb' - - 'spec/services/iiif_collection_thumbnail_path_service_spec.rb' - - 'spec/services/iiif_work_thumbnail_path_service_spec.rb' - - 'spec/routing/proprietor/accounts_routing_spec.rb' + - 'hyrax.gemspec' + - 'app/models/concerns/hyrax/content_block_behavior.rb' + - 'app/services/hyrax/workflow/workflow_schema.rb' + - 'config/initializers/simple_form.rb' + - 'config/features.rb' + - 'config/routes.rb' + - 'lib/generators/hyrax/templates/catalog_controller.rb' + - 'lib/generators/hyrax/templates/config/initializers/simple_form_bootstrap.rb' + - 'lib/hyrax/rails/routes.rb' + - 'lib/tasks/*.rake' + - 'spec/**/*.rb' + - 'tasks/benchmark.rake' -Layout/IndentationConsistency: - EnforcedStyle: rails +Style/AsciiComments: + Enabled: false -Layout/DotPosition: - EnforcedStyle: leading +# rubocop suggests !thing.nil? instead, but that is NOT equivalent +Style/DoubleNegation: + Enabled: false -Style/Documentation: +Style/CollectionMethods: + PreferredMethods: + collect: 'map' + collect!: 'map!' + inject: 'reduce' + detect: 'find' + find_all: 'select' + +Style/SymbolArray: Enabled: false -Style/StringLiterals: +Style/ClassAndModuleChildren: Enabled: false -Style/WordArray: +Style/SingleLineBlockParams: Enabled: false -Metrics/ClassLength: - Exclude: - - 'app/controllers/catalog_controller.rb' +Rails/ApplicationJob: + Enabled: false + +Rails/ApplicationMailer: + Enabled: false -Metrics/ModuleLength: - Max: 200 +Rails/ApplicationRecord: + Enabled: false Rails/HasAndBelongsToMany: Exclude: - 'app/models/role.rb' -RSpec/AnyInstance: +Rails/HasManyOrHasOneDependent: + Exclude: + - 'app/models/endpoint.rb' + +Rails/RakeEnvironment: Enabled: false -RSpec/InstanceVariable: +# We define custom methods like `find_by_user_key`, +# `find_by_created_date`, etc +Rails/DynamicFindBy: + Enabled: false + +Rails/FilePath: Exclude: - - 'spec/controllers/hyku/registrations_controller_spec.rb' + - 'spec/abilities/**/*' -RSpec/NamedSubject: - Enabled: false +Rails/OutputSafety: + Exclude: + - 'app/builders/hyrax/form_builder.rb' + - 'app/helpers/hyrax/citations_behaviors/formatters/apa_formatter.rb' + - 'app/helpers/hyrax/citations_behaviors/formatters/chicago_formatter.rb' + - 'app/helpers/hyrax/citations_behaviors/formatters/mla_formatter.rb' + - 'app/helpers/hyrax/collections_helper.rb' + - 'app/helpers/hyrax/content_block_helper_behavior.rb' + - 'app/helpers/hyrax/hyrax_helper_behavior.rb' + - 'app/presenters/hyrax/fixity_status_presenter.rb' + - 'app/presenters/hyrax/presents_attributes.rb' + - 'app/renderers/hyrax/renderers/attribute_renderer.rb' + - 'spec/views/hyrax/my/works/_list_works.html.erb_spec.rb' + +Rails/UniqueValidationWithoutIndex: + Exclude: + - 'app/models/account.rb' + - 'app/models/domain_name.rb' + - 'app/models/hyrax/group.rb' RSpec/DescribeClass: Exclude: - - 'spec/requests/**/*' + - 'spec/abilities/**/*' + - 'spec/config/hyrax_events_spec.rb' + - 'spec/conversions/**/*' - 'spec/features/**/*' + - 'spec/inputs/**/*' + - 'spec/javascripts/jasmine_spec.rb' + - 'spec/tasks/rake_spec.rb' - 'spec/views/**/*' - - 'spec/routing/**/*' - - 'spec/tasks/**/*' -Rails/FilePath: - Exclude: - - 'spec/routing/**/*' +# # By default RSpec/MessageSpies has the following: +# # Prefer have_received for setting message expectations. Setup form as a spy using allow or instance_spy. +# # The default assumes EnforcedStyle is 'have_received'. Most of our specs are 'receive' +RSpec/MessageSpies: + Enabled: false RSpec/ExpectActual: - Exclude: - - 'spec/routing/**/*' + Enabled: false -RSpec/VerifiedDoubles: +RSpec/LetSetup: Enabled: false RSpec/MessageExpectation: Enabled: false -# By default RSpec/MessageSpies has the following: -# Prefer have_received for setting message expectations. Setup form as a spy using allow or instance_spy. -RSpec/MessageSpies: - Enabled: true - EnforcedStyle: receive - -RSpec/ExampleLength: - Max: 20 - RSpec/NestedGroups: - Max: 4 - -RSpec/MultipleExpectations: Enabled: false -Metrics/BlockLength: - Exclude: - - 'spec/**/*.rb' - - 'lib/tasks/*.rake' - - 'app/controllers/catalog_controller.rb' +RSpec/LeadingSubject: + Enabled: false diff --git a/.rubocop_fixme.yml b/.rubocop_fixme.yml new file mode 100644 index 000000000..964bae6dc --- /dev/null +++ b/.rubocop_fixme.yml @@ -0,0 +1,201 @@ +Security/MarshalLoad: + Exclude: + - 'app/models/concerns/hyrax/user.rb' + +Metrics/ClassLength: + Exclude: + - 'app/controllers/hyrax/dashboard/collections_controller.rb' + - 'app/controllers/hyrax/admin/admin_sets_controller.rb' + - 'app/controllers/hyrax/batch_edits_controller.rb' + - 'app/controllers/hyrax/downloads_controller.rb' + - 'app/controllers/hyrax/file_sets_controller.rb' + - 'app/forms/hyrax/forms/permission_template_form.rb' + - 'app/presenters/hyrax/work_show_presenter.rb' + - 'app/presenters/hyrax/collection_presenter.rb' + - 'app/services/hyrax/user_stat_importer.rb' + - 'lib/generators/hyrax/templates/catalog_controller.rb' + - 'lib/generators/hyrax/install_generator.rb' + - 'lib/hyrax/configuration.rb' + +Metrics/ParameterLists: + Exclude: + - 'app/jobs/batch_create_job.rb' + +Metrics/ModuleLength: + Exclude: + - 'app/controllers/concerns/hyrax/works_controller_behavior.rb' + - 'app/helpers/hyrax/hyrax_helper_behavior.rb' + - 'app/models/concerns/hyrax/ability.rb' + - 'app/services/hyrax/workflow/permission_query.rb' + - 'spec/services/hyrax/workflow/permission_query_spec.rb' + # TODO: extract CollectionAccessControls or something, so we don't have to skip this check? + - 'app/models/concerns/hyrax/collection_behavior.rb' + +RSpec/NamedSubject: + Enabled: false + +RSpec/ExampleLength: + Max: 9 + Exclude: + - 'spec/actors/hyrax/actors/file_set_actor_spec.rb' + - 'spec/actors/hyrax/actors/generic_work_actor_spec.rb' + - 'spec/controllers/hyrax/api/items_controller_spec.rb' + - 'spec/controllers/hyrax/batch_edits_controller_spec.rb' + - 'spec/controllers/hyrax/batch_uploads_controller_spec.rb' + - 'spec/controllers/hyrax/file_sets_controller_spec.rb' + - 'spec/controllers/hyrax/generic_works_controller_spec.rb' + - 'spec/controllers/hyrax/my/highlights_controller_spec.rb' + - 'spec/controllers/hyrax/transfers_controller_spec.rb' + - 'spec/forms/hyrax/forms/collection_form_spec.rb' + - 'spec/forms/hyrax/forms/batch_edit_form_spec.rb' + - 'spec/forms/hyrax/forms/batch_upload_form_spec.rb' + - 'spec/forms/hyrax/forms/file_set_edit_form_spec.rb' + - 'spec/features/**/*' + - 'spec/helpers/hyrax/charts_helper_spec.rb' + - 'spec/helpers/dashboard_helper_spec.rb' + - 'spec/helpers/hyrax_helper_spec.rb' + - 'spec/indexers/hyrax/file_set_indexer_spec.rb' + - 'spec/javascripts/jasmine_spec.rb' + - 'spec/jobs/file_set_attached_event_job_spec.rb' + - 'spec/jobs/batch_create_job_spec.rb' + - 'spec/jobs/create_work_job_spec.rb' + - 'spec/jobs/content_update_event_job_spec.rb' + - 'spec/jobs/content_restored_version_event_job_spec.rb' + - 'spec/jobs/content_new_version_event_job_spec.rb' + - 'spec/jobs/content_depositor_change_event_job_spec.rb' + - 'spec/jobs/change_depositor_event_job_spec.rb' + - 'spec/jobs/content_deposit_event_job_spec.rb' + - 'spec/jobs/content_delete_event_job_spec.rb' + - 'spec/jobs/ingest_file_job_spec.rb' + - 'spec/lib/hyrax/arkivo/actor_spec.rb' + - 'spec/lib/hyrax/resource_sync/capability_list_writer_spec.rb' + - 'spec/models/checksum_audit_log_spec.rb' + - 'spec/models/featured_work_spec.rb' + - 'spec/models/file_set_spec.rb' + - 'spec/models/generic_work_spec.rb' + - 'spec/presenters/hyrax/inspect_work_presenter_spec.rb' + - 'spec/services/hyrax/actor_factory_spec.rb' + - 'spec/services/hyrax/admin_set_create_service_spec.rb' + - 'spec/services/hyrax/default_middleware_stack_spec.rb' + - 'spec/services/hyrax/graph_exporter_spec.rb' + - 'spec/services/hyrax/user_stat_importer_spec.rb' + - 'spec/services/hyrax/workflow/activate_object_spec.rb' + - 'spec/services/hyrax/workflow/deactivate_object_spec.rb' + - 'spec/services/hyrax/workflow/permission_generator_spec.rb' + - 'spec/services/hyrax/workflow/permission_query_spec.rb' + - 'spec/services/hyrax/workflow/state_machine_generator_spec.rb' + - 'spec/services/hyrax/workflow/workflow_importer_spec.rb' + - 'spec/views/**/*' + - 'spec/wings/valkyrie/persister_spec.rb' + +RSpec/VerifiedDoubles: + Enabled: false + +RSpec/SubjectStub: + Exclude: + - 'spec/actors/hyrax/actors/generic_work_actor_spec.rb' + - 'spec/controllers/hyrax/file_sets_controller_spec.rb' + - 'spec/models/file_set_spec.rb' + - 'spec/models/hyrax/work_behavior_spec.rb' + - 'spec/search_builders/hyrax/file_set_search_builder_spec.rb' + - 'spec/models/hyrax/operation_spec.rb' + - 'spec/controllers/hyrax/accepts_batches_controller_spec.rb' + - 'spec/indexers/hyrax/repository_reindexer_spec.rb' + - 'spec/lib/hyrax/analytics_spec.rb' + - 'spec/models/job_io_wrapper_spec.rb' + - 'spec/search_builders/hyrax/abstract_type_relation_spec.rb' + - 'spec/services/hyrax/database_migrator_spec.rb' + +RSpec/AnyInstance: + Exclude: + - 'spec/actors/hyrax/actors/generic_work_actor_spec.rb' + - 'spec/controllers/hyrax/api/items_controller_spec.rb' + - 'spec/controllers/hyrax/api/zotero_controller_spec.rb' + - 'spec/controllers/hyrax/batch_edits_controller_spec.rb' + - 'spec/controllers/hyrax/stats_controller_spec.rb' + - 'spec/controllers/hyrax/users_controller_spec.rb' + - 'spec/hyrax/transactions/steps/delete_access_control_spec.rb' + - 'spec/hyrax/transactions/steps/save_access_control_spec.rb' + - 'spec/jobs/content_restored_version_event_job_spec.rb' + - 'spec/jobs/file_set_attached_event_job_spec.rb' + - 'spec/jobs/hyrax/grant_edit_to_members_job_spec.rb' + - 'spec/jobs/hyrax/grant_read_to_members_job_spec.rb' + - 'spec/jobs/hyrax/revoke_edit_from_members_job_spec.rb' + - 'spec/lib/hyrax/arkivo/create_subscription_job_spec.rb' + - 'spec/presenters/hyrax/file_usage_spec.rb' + - 'spec/presenters/hyrax/work_usage_spec.rb' + - 'spec/services/hyrax/repository_fixity_check_service_spec.rb' + - 'spec/services/hyrax/workflow/permission_generator_spec.rb' + - 'spec/services/hyrax/workflow/sipity_actions_generator_spec.rb' + - 'spec/services/hyrax/workflow/state_machine_generator_spec.rb' + - 'spec/services/hyrax/workflow/workflow_permissions_generator_spec.rb' + - 'spec/controllers/hyrax/homepage_controller_spec.rb' + - 'spec/controllers/hyrax/my/collections_controller_spec.rb' + - 'spec/controllers/hyrax/my/works_controller_spec.rb' + - 'spec/presenters/hyrax/admin/repository_object_presenter_spec.rb' + +# Offense count: 51 +RSpec/ExpectInHook: + Enabled: false + +# Offense count: 27 +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: and_return, block +RSpec/ReturnFromStub: + Exclude: + - 'spec/controllers/hyrax/api/items_controller_spec.rb' + - 'spec/controllers/hyrax/file_sets_controller_spec.rb' + - 'spec/lib/hyrax/arkivo/create_subscription_job_spec.rb' + - 'spec/models/file_set_spec.rb' + - 'spec/presenters/hyrax/admin_set_options_presenter_spec.rb' + - 'spec/routing/api_route_spec.rb' + - 'spec/views/_user_util_links.html.erb_spec.rb' + - 'spec/views/hyrax/base/_attributes.html.erb_spec.rb' + - 'spec/views/hyrax/base/_form.html.erb_spec.rb' + - 'spec/views/hyrax/base/file_manager.html.erb_spec.rb' + - 'spec/views/hyrax/dashboard/profiles/edit.html.erb_spec.rb' + - 'spec/views/hyrax/users/_user_info.html.erb_spec.rb' + +# Offense count: 26 +RSpec/RepeatedDescription: + Exclude: + - 'spec/models/sipity/agent_spec.rb' + - 'spec/models/sipity/comment_spec.rb' + - 'spec/models/sipity/entity_spec.rb' + - 'spec/models/sipity/entity_specific_responsibility_spec.rb' + - 'spec/models/sipity/role_spec.rb' + - 'spec/models/sipity/workflow_action_spec.rb' + - 'spec/models/sipity/workflow_responsibility_spec.rb' + - 'spec/models/sipity/workflow_role_spec.rb' + - 'spec/models/sipity/workflow_state_action_permission_spec.rb' + - 'spec/models/sipity/workflow_state_action_spec.rb' + - 'spec/models/sipity/workflow_state_spec.rb' + +# Offense count: 2 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/HasManyOrHasOneDependent: + Exclude: + - 'app/models/admin_set.rb' + - 'app/models/hyrax/permission_template.rb' + +# Offense count: 1 +Rails/SkipsModelValidations: + Exclude: + - 'app/services/hyrax/works/migration_service.rb' + +# Offense count: 12 +Lint/MissingSuper: + Exclude: + - 'app/actors/hyrax/actors/interpret_visibility_actor.rb' + - 'app/actors/hyrax/actors/ordered_members_actor.rb' + - 'app/models/concerns/hyrax/file_set/characterization.rb' + - 'app/presenters/hyrax/file_usage.rb' + - 'app/presenters/hyrax/work_usage.rb' + - 'app/services/hyrax/batch_create_failure_service.rb' + - 'app/services/hyrax/batch_create_success_service.rb' + - 'app/services/hyrax/collection_types/create_service.rb' + - 'app/services/hyrax/solr_query_service.rb' + - 'lib/hyrax/form_fields.rb' + - 'lib/hyrax/health_checks/solr_check.rb' + - 'lib/hyrax/schema.rb' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 902a16471..ad19a7fd2 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,186 +1,139 @@ # This configuration was generated by -# `rubocop --auto-gen-config` -# on 2020-05-15 17:53:23 +0000 using RuboCop version 0.52.1. +# `rubocop --auto-gen-config --no-auto-gen-timestamp` +# using RuboCop version 1.28.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 1 -Lint/AmbiguousBlockAssociation: - Exclude: - - 'app/controllers/catalog_controller.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect. -# SupportedStylesAlignWith: keyword, variable, start_of_line -Lint/EndAlignment: +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, AllowAdjacentOneLineDefs, NumberOfEmptyLines. +Layout/EmptyLineBetweenDefs: Exclude: - - 'app/helpers/blacklight/catalog_helper_behavior.rb' + - 'app/jobs/bulkrax/import_file_set_job.rb' + - 'app/models/bulkrax/entry.rb' # Offense count: 2 -Lint/UselessAssignment: +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, no_empty_lines +Layout/EmptyLinesAroundBlockBody: Exclude: - - 'app/forms/hyrax/forms/admin/appearance.rb' - - 'spec/controllers/proprietor/users_controller_spec.rb' - -# Offense count: 10 -Metrics/AbcSize: - Max: 49 + - 'spec/rails_helper.rb' # Offense count: 3 -# Configuration parameters: CountComments. -Metrics/ClassLength: - Max: 112 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'app/parsers/bulkrax/csv_parser.rb' + - 'spec/models/bulkrax/rdf_entry_spec.rb' + - 'spec/models/bulkrax/xml_entry_spec.rb' -# Offense count: 2 -Metrics/CyclomaticComplexity: - Max: 12 +# Offense count: 1 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: Width, AllowedPatterns, IgnoredPatterns. +Layout/IndentationWidth: + Exclude: + - 'spec/rails_helper.rb' -# Offense count: 23 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# Offense count: 8 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns. # URISchemes: http, https -Metrics/LineLength: - Max: 376 - -# Offense count: 7 -# Configuration parameters: CountComments. -Metrics/MethodLength: - Max: 35 +Layout/LineLength: + Max: 301 # Offense count: 1 -# Configuration parameters: CountComments. -Metrics/ModuleLength: - Max: 168 - -# Offense count: 2 -Metrics/PerceivedComplexity: - Max: 14 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineMethodCallBraceLayout: + Exclude: + - 'app/parsers/bulkrax/csv_parser.rb' # Offense count: 1 -# Configuration parameters: Blacklist. -# Blacklist: END, (?-mix:EO[A-Z]{1}) -Naming/HeredocDelimiterNaming: +# This cop supports safe auto-correction (--auto-correct). +Layout/RescueEnsureAlignment: Exclude: - - 'spec/jobs/import_work_from_purl_job_spec.rb' - -# Offense count: 6 -# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros. -# NamePrefix: is_, has_, have_ -# NamePrefixBlacklist: is_, has_, have_ -# NameWhitelist: is_a? -# MethodDefinitionMacros: define_method, define_singleton_method -Naming/PredicateName: - Exclude: - - 'spec/**/*' - - 'app/controllers/application_controller.rb' - - 'app/helpers/blacklight/catalog_helper_behavior.rb' - - 'app/models/user.rb' + - 'spec/rails_helper.rb' -# Offense count: 6 -RSpec/BeforeAfterAll: - Exclude: - - 'spec/spec_helper.rb' +# Offense count: 7 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: AllowInHeredoc. +Layout/TrailingWhitespace: + Exclude: + - 'app/models/bulkrax/csv_entry.rb' + - 'app/parsers/bulkrax/csv_parser.rb' + - 'spec/models/bulkrax/rdf_entry_spec.rb' + - 'spec/models/bulkrax/xml_entry_spec.rb' - 'spec/rails_helper.rb' - - 'spec/support/**/*.rb' - - 'spec/models/hyku/group_spec.rb' - - 'spec/models/uploaded_file_spec.rb' - - 'spec/tasks/rake_spec.rb' -# Offense count: 85 -# Configuration parameters: Prefixes. -# Prefixes: when, with, without -RSpec/ContextWording: - Enabled: false +# Offense count: 16 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 42 -# Offense count: 3 -RSpec/ExpectInHook: - Exclude: - - 'spec/controllers/sites_controller_spec.rb' - - 'spec/models/uploaded_file_spec.rb' +# Offense count: 4 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 201 -# Offense count: 1 -RSpec/IteratedExpectation: - Exclude: - - 'spec/tasks/rake_spec.rb' +# Offense count: 13 +# Configuration parameters: IgnoredMethods. +Metrics/CyclomaticComplexity: + Max: 19 -# Offense count: 4 -RSpec/LetSetup: - Exclude: - - 'spec/models/account_spec.rb' - - 'spec/models/role_spec.rb' - - 'spec/models/user_spec.rb' +# Offense count: 32 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +Metrics/MethodLength: + Max: 26 # Offense count: 2 -RSpec/MessageChain: - Exclude: - - 'spec/views/shared/select_work_type_modal.html.erb_spec.rb' +# Configuration parameters: CountComments, CountAsOne. +Metrics/ModuleLength: + Max: 131 -# Offense count: 8 -RSpec/ScatteredLet: - Exclude: - - 'spec/controllers/account_sign_up_controller_spec.rb' - - 'spec/controllers/admin/accounts_controller_spec.rb' - - 'spec/controllers/proprietor/accounts_controller_spec.rb' - - 'spec/jobs/import_work_from_purl_job_spec.rb' +# Offense count: 9 +# Configuration parameters: IgnoredMethods. +Metrics/PerceivedComplexity: + Max: 19 # Offense count: 1 # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/HasManyOrHasOneDependent: Exclude: - - 'app/models/endpoint.rb' + - 'app/models/concerns/bulkrax/status_info.rb' -# Offense count: 5 -Rails/OutputSafety: - Exclude: - - 'app/forms/hyrax/forms/admin/appearance.rb' - - 'app/helpers/blacklight/catalog_helper_behavior.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: AutoCorrect, EnforcedStyle. -# SupportedStyles: nested, compact -Style/ClassAndModuleChildren: - Exclude: - - 'app/helpers/blacklight/catalog_helper_behavior.rb' - -# Offense count: 3 -# Configuration parameters: EnforcedStyle. -# SupportedStyles: annotated, template, unannotated -Style/FormatStringToken: +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +# Configuration parameters: Keywords, RequireColon. +# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW, NOTE +Style/CommentAnnotation: Exclude: - - 'app/models/account.rb' - - 'spec/models/account_spec.rb' + - 'app/models/bulkrax/xml_entry.rb' + - 'spec/models/bulkrax/oai_entry_spec.rb' -# Offense count: 4 -# Configuration parameters: MinBodyLength. -Style/GuardClause: +# Offense count: 2 +# This cop supports safe auto-correction (--auto-correct). +Style/IfUnlessModifier: Exclude: - - 'app/controllers/application_controller.rb' - - 'app/controllers/hyrax/downloads_controller.rb' - - 'app/helpers/blacklight/catalog_helper_behavior.rb' - - 'app/models/bulkrax/entry.rb' + - 'app/models/bulkrax/csv_entry.rb' + - 'lib/generators/bulkrax/templates/config/initializers/bulkrax.rb' # Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: line_count_dependent, lambda, literal -Style/Lambda: +# This cop supports safe auto-correction (--auto-correct). +Style/MultilineIfModifier: Exclude: - - 'app/models/user.rb' + - 'app/models/bulkrax/csv_entry.rb' # Offense count: 1 -Style/MixinUsage: +# This cop supports safe auto-correction (--auto-correct). +Style/RedundantBegin: Exclude: - - 'spec/support/devise.rb' - -# Offense count: 2 -# Cop supports --auto-correct. -# Configuration parameters: AutoCorrect, EnforcedStyle. -# SupportedStyles: predicate, comparison -Style/NumericPredicate: - Exclude: - - 'spec/**/*' - - 'app/helpers/blacklight/catalog_helper_behavior.rb' + - 'spec/rails_helper.rb' diff --git a/Dockerfile b/Dockerfile index 8916c378e..325d61452 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ -ARG HYRAX_IMAGE_VERSION=hyrax-v4.0.0.rc1 -ARG RUBY_VERSION=2.7.7 +ARG HYRAX_IMAGE_VERSION=hyrax-v5.0.0.rc1 FROM ghcr.io/samvera/hyrax/hyrax-base:$HYRAX_IMAGE_VERSION as hyku-base USER root diff --git a/Gemfile b/Gemfile index 3fd4a6453..9198442bb 100644 --- a/Gemfile +++ b/Gemfile @@ -4,19 +4,23 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 5.2.5' +gem 'rails', '~> 6.0' -gem 'active-fedora', '>= 11.1.4' gem 'active_elastic_job', github: 'active-elastic-job/active-elastic-job', ref: 'ec51c5d9dedc4a1b47f2db41f26d5fceb251e979', group: %i[aws] +gem 'active-fedora', '~> 14.0' gem 'activerecord-nulldb-adapter' gem 'addressable', '2.8.1' # remove once https://github.com/postrank-labs/postrank-uri/issues/49 is fixed -gem 'apartment' +gem 'apartment', github: 'scientist-softserv/apartment', branch: 'development' gem 'aws-sdk-sqs', group: %i[aws] -gem 'blacklight', '~> 6.7' -gem 'blacklight_oai_provider', '~> 6.1', '>= 6.1.1' +gem 'bixby', '~> 5.0', '>= 5.0.2', group: %i[development test] +gem 'blacklight', '~> 7.29' +gem 'blacklight_advanced_search' +gem 'blacklight_oai_provider', '~> 7.0' +gem 'blacklight_range_limit' gem 'bolognese', '>= 1.9.10' +gem 'bootstrap', '~> 4.6' gem 'bootstrap-datepicker-rails' -gem 'bulkrax', '~> 5.3' +gem 'bulkrax', '~> 5.4' gem 'byebug', group: %i[development test] gem 'capybara', group: %i[test] gem 'capybara-screenshot', '~> 1.0', group: %i[test] @@ -28,16 +32,17 @@ gem 'database_cleaner', group: %i[test] gem 'devise' gem 'devise-guests', '~> 0.3' gem 'devise-i18n' -gem 'devise_invitable', '~> 1.6' -gem 'dry-monads', '~> 1.4.0' # Locked because 1.5.0 was not compatible with Hyrax v.3.4.2 +gem 'devise_invitable', '~> 2.0' +gem 'dry-monads', '~> 1.5' gem 'easy_translate', group: %i[development] gem 'factory_bot_rails', group: %i[test] gem 'fcrepo_wrapper', '~> 0.4', group: %i[development test] -gem 'flipflop', '~> 2.6.0' # waiting for hyrax 4 upgrade gem 'flutie' -gem 'hyrax', '~> 3.5.0' -gem 'hyrax-doi', github: 'samvera-labs/hyrax-doi', branch: 'main' -gem 'hyrax-iiif_av', github: 'samvera-labs/hyrax-iiif_av', branch: 'main' +gem 'good_job', '~> 2.99' +gem 'googleauth', '= 1.8.1' # 1.9.0 got yanked from rubygems, hard pinning until we can upgrade +gem 'hyrax', github: 'samvera/hyrax', branch: 'double_combo' +gem 'hyrax-doi', github: 'samvera-labs/hyrax-doi', branch: 'rails_hyrax_upgrade' +gem 'hyrax-iiif_av', github: 'samvera-labs/hyrax-iiif_av', branch: 'rails_hyrax_upgrade' gem 'i18n-debug', require: false, group: %i[development test] gem 'i18n-tasks', group: %i[development test] gem 'iiif_print', github: 'scientist-softserv/iiif_print', branch: 'main' @@ -53,30 +58,33 @@ gem 'negative_captcha' gem 'okcomputer' gem 'omniauth-cas', github: 'stanhu/omniauth-cas', ref: '4211e6d05941b4a981f9a36b49ec166cecd0e271' gem 'omniauth-multi-provider' +gem 'omniauth_openid_connect' gem 'omniauth-rails_csrf_protection', '~> 1.0' gem 'omniauth-saml', '~> 2.1' -gem 'omniauth_openid_connect' -gem 'parser', '~> 2.5.3' +gem 'order_already' +gem 'parser', '>= 3.1.0.0' gem 'pg' gem 'postrank-uri', '>= 1.0.24' gem 'pry-byebug', group: %i[development test] gem 'puma', '~> 5.6' # Use Puma as the app server gem 'rack-test', '0.7.0', group: %i[test] # rack-test >= 0.71 does not work with older Capybara versions (< 2.17). See #214 for more details gem 'rails-controller-testing', group: %i[test] -gem 'rdf', '~> 3.1.15' # rdf 3.2.0 removed SerializedTransaction which ldp requires +gem 'rdf', '~> 3.2' +gem 'redis-namespace', '~> 1.10' # Hyrax v5 relies on 1.5; but we'd like to have the #clear method so we need 1.10 or greater. gem 'redlock', '>= 0.1.2', '< 2.0' # lock redlock per https://github.com/samvera/hyrax/pull/5961 -gem 'riiif', '~> 1.1' +gem 'riiif', '~> 2.0' gem 'rolify' gem 'rsolr', '~> 2.0' gem 'rspec', group: %i[development test] gem 'rspec-activemodel-mocks', group: %i[test] gem 'rspec-its', group: %i[test] +gem 'rspec_junit_formatter', group: %i[test] gem 'rspec-rails', '>= 3.6.0', group: %i[development test] gem 'rspec-retry', group: %i[test] -gem 'rspec_junit_formatter', group: %i[test] -gem 'rubocop', '~> 0.50', '<= 0.52.1', group: %i[development test] +gem 'rubocop', '1.28.2', group: %i[development test] +gem 'rubocop-rails', '~> 2.15', group: %i[development test] gem 'rubocop-rspec', '~> 1.22', '<= 1.22.2', group: %i[development test] -gem 'sass-rails', '~> 5.0' # Use SCSS for stylesheets +gem 'sass-rails', '~> 6.0' # Use SCSS for stylesheets gem 'scss_lint', require: false, group: %i[development] gem 'secure_headers' gem 'selenium-webdriver', '4.8.1', group: %i[test] @@ -89,6 +97,7 @@ gem 'spring-watcher-listen', '~> 2.0.0', group: %i[development] gem 'terser' # to support the Safe Navigation / Optional Chaining operator (?.) and avoid uglifier precompile issue gem 'tether-rails' gem 'turbolinks', '~> 5' +gem 'twitter-typeahead-rails', '0.11.1.pre.corejavascript' gem 'web-console', '>= 3.3.0', group: %i[development] # <%= console %> in views gem 'webdrivers', '~> 4.7.0', group: %i[test] gem 'webmock', group: %i[test] diff --git a/Gemfile.lock b/Gemfile.lock index 651139ee2..9e330d35d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,47 +9,116 @@ GIT GIT remote: https://github.com/samvera-labs/hyku_knapsack.git - revision: 446f16b928f7f12125fdaaf6feb08dcdacf1bd38 + revision: 14f688b61afab9ee886f5f7fa26a76a37bced597 branch: upstream_main specs: hyku_knapsack (0.0.1) rails (>= 5.2.0) - sentry-raven GIT remote: https://github.com/samvera-labs/hyrax-doi.git - revision: d494a50ef8ce3eae594c7ed7148c33b3c977d4a7 - branch: main + revision: 9b7ab7f8054a14385b838de1118f55ad2e0f5da8 + branch: rails_hyrax_upgrade specs: hyrax-doi (0.2.0) - bolognese (~> 1.8, >= 1.8.6) + bolognese (>= 1.8.6, < 2.0) flipflop (~> 2.3) - hyrax (>= 2.9, < 4.0) - rails (~> 5.2.4, >= 5.2.4.3) + hyrax (>= 2.9, < 6.0) + rails (>= 5.2.4.3, < 8.0) GIT remote: https://github.com/samvera-labs/hyrax-iiif_av.git - revision: 6273f90016c153d2add33f85cc24285d51a25382 - branch: main + revision: 66a94059f192a295bfb4503d247986f16b183330 + branch: rails_hyrax_upgrade specs: hyrax-iiif_av (0.2.0) blacklight - hyrax (>= 2.9, < 4.0) + hyrax (>= 3.5, < 6.0) iiif_manifest (> 0.5) - rails (~> 5.1) + rails (>= 5.1, < 8.0) + +GIT + remote: https://github.com/samvera/hyrax.git + revision: b7891b758411c59f71ff54212e0d250fcc47e35f + branch: double_combo + specs: + hyrax (5.0.0.rc2) + active-fedora (~> 14.0) + almond-rails (~> 0.1) + awesome_nested_set (~> 3.1) + blacklight (~> 7.29) + blacklight-gallery (~> 4.0) + breadcrumbs_on_rails (~> 3.0) + browse-everything (>= 0.16, < 2.0) + carrierwave (~> 1.0) + clipboard-rails (~> 1.5) + concurrent-ruby (~> 1.0) + connection_pool (~> 2.4) + draper (~> 4.0) + dry-container (~> 0.11) + dry-events (~> 1.0, >= 1.0.1) + dry-logic (~> 1.5) + dry-monads (~> 1.6) + dry-validation (~> 1.10) + flipflop (~> 2.3) + flot-rails (~> 0.0.6) + font-awesome-rails (~> 4.2) + hydra-derivatives (~> 3.3) + hydra-editor (~> 6.0) + hydra-file_characterization (~> 1.1) + hydra-head (~> 12.0) + hydra-works (>= 0.16) + iiif_manifest (>= 0.3, < 2.0) + json-schema + legato (~> 0.3) + linkeddata + mailboxer (~> 0.12) + nest (~> 3.1) + noid-rails (~> 3.0) + oauth + oauth2 (~> 1.2) + openseadragon + posix-spawn + qa (~> 5.5, >= 5.5.1) + rails (~> 6.1) + rails_autolink (~> 1.1) + rdf-rdfxml + rdf-vocab (~> 3.0) + redis (~> 4.0) + redis-namespace (~> 1.5) + redlock (>= 0.1.2, < 2.0) + reform (~> 2.3) + reform-rails (~> 0.2.0) + retriable (>= 2.9, < 4.0) + sass-rails (~> 6.0) + select2-rails (~> 3.5) + signet + sprockets (~> 3.7) + tinymce-rails (~> 5.10) + valkyrie (~> 3.1.1) + view_component (~> 2.74.1) + +GIT + remote: https://github.com/scientist-softserv/apartment.git + revision: 9ad4b0ef2ee6debb956e86ef9e7095c8358fef5e + branch: development + specs: + apartment (2.2.1) + activerecord (>= 3.1.2, < 7.0) + parallel (>= 0.7.1) + public_suffix (>= 2) + rack (>= 1.3.6) GIT remote: https://github.com/scientist-softserv/iiif_print.git - revision: 9e7837ce4bd08bf8fff9126455d0e0e2602f6018 + revision: 2dfd14b0fc9805c362b5442fcb90d7eaa58ae630 branch: main specs: iiif_print (1.0.0) - blacklight_iiif_search (~> 1.0) + blacklight_iiif_search (>= 1.0, < 3.0) derivative-rodeo (~> 0.5) - dry-monads (~> 1.4.0) - hyrax (>= 2.5, < 4) + hyrax (>= 2.5, < 6) nokogiri (>= 1.13.2) - rails (~> 5.0) rdf-vocab (~> 3.0) GIT @@ -65,35 +134,50 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (5.2.8.1) - actionpack (= 5.2.8.1) + actioncable (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) + actionmailbox (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + mail (>= 2.7.1) + actionmailer (6.1.7.6) + actionpack (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activesupport (= 6.1.7.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.8.1) - actionview (= 5.2.8.1) - activesupport (= 5.2.8.1) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.7.6) + actionview (= 6.1.7.6) + activesupport (= 6.1.7.6) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.6) + actionpack (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + nokogiri (>= 1.8.5) + actionview (6.1.7.6) + activesupport (= 6.1.7.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - active-fedora (13.3.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + active-fedora (14.0.1) active-triples (>= 0.11.0, < 2.0.0) activemodel (>= 5.1) activesupport (>= 5.1) deprecation - faraday (~> 0.12) + faraday (>= 1.0) faraday-encoding (>= 0.0.5) ldp (>= 0.7.0, < 2) rsolr (>= 1.1.2, < 3) @@ -106,68 +190,64 @@ GEM active_encode (0.8.2) rails sprockets (< 4) - activejob (5.2.8.1) - activesupport (= 5.2.8.1) + activejob (6.1.7.6) + activesupport (= 6.1.7.6) globalid (>= 0.3.6) - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) + activemodel (6.1.7.6) + activesupport (= 6.1.7.6) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) - activerecord-import (1.4.1) + activerecord (6.1.7.6) + activemodel (= 6.1.7.6) + activesupport (= 6.1.7.6) + activerecord-import (1.5.1) activerecord (>= 4.2) - activerecord-nulldb-adapter (0.9.0) - activerecord (>= 5.2.0, < 7.1) - activestorage (5.2.8.1) - actionpack (= 5.2.8.1) - activerecord (= 5.2.8.1) - marcel (~> 1.0.0) - activesupport (5.2.8.1) + activerecord-nulldb-adapter (1.0.1) + activerecord (>= 5.2.0, < 7.2) + activestorage (6.1.7.6) + actionpack (= 6.1.7.6) + activejob (= 6.1.7.6) + activerecord (= 6.1.7.6) + activesupport (= 6.1.7.6) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.6) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.1) public_suffix (>= 2.0.2, < 6.0) aes_key_wrap (1.1.0) almond-rails (0.3.0) rails (>= 4.2) - amazing_print (1.4.0) - apartment (2.2.1) - activerecord (>= 3.1.2, < 6.0) - parallel (>= 0.7.1) - public_suffix (>= 2) - rack (>= 1.3.6) - arel (9.0.0) ast (2.4.2) attr_required (1.0.1) - autoprefixer-rails (10.4.13.0) + autoprefixer-rails (10.4.16.0) execjs (~> 2) - awesome_nested_set (3.5.0) - activerecord (>= 4.0.0, < 7.1) - aws-eventstream (1.2.0) - aws-partitions (1.785.0) - aws-sdk-core (3.178.0) - aws-eventstream (~> 1, >= 1.0.2) + awesome_nested_set (3.6.0) + activerecord (>= 4.0.0, < 7.2) + aws-eventstream (1.3.0) + aws-partitions (1.865.0) + aws-sdk-core (3.190.0) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.64.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (1.74.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.121.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-s3 (1.141.0) + aws-sdk-core (~> 3, >= 3.189.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sdk-sqs (1.61.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sigv4 (~> 1.8) + aws-sdk-sqs (1.69.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sigv4 (1.6.0) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babel-source (5.8.35) babel-transpiler (0.7.0) @@ -176,49 +256,63 @@ GEM bagit (0.4.6) docopt (~> 0.5.0) validatable (~> 1.6) + base64 (0.2.0) bcp47 (0.3.3) i18n - bcrypt (3.1.18) + bcp47_spec (0.2.1) + bcrypt (3.1.20) benchmark_methods (0.7) - better_html (1.0.16) - actionview (>= 4.0) - activesupport (>= 4.0) + better_html (2.0.2) + actionview (>= 6.0) + activesupport (>= 6.0) ast (~> 2.0) erubi (~> 1.4) - html_tokenizer (~> 0.0.6) parser (>= 2.4) smart_properties bibtex-ruby (6.0.0) latex-decode (~> 0.0) + bigdecimal (3.1.5) bindata (2.4.15) bindex (0.8.1) - blacklight (6.25.0) - bootstrap-sass (~> 3.2) + bixby (5.0.2) + rubocop (= 1.28.2) + rubocop-ast + rubocop-performance + rubocop-rails + rubocop-rspec + blacklight (7.35.0) deprecation globalid + hashdiff + i18n (>= 1.7.0) jbuilder (~> 2.7) kaminari (>= 0.15) - nokogiri (~> 1.6) - rails (>= 4.2, < 6) - rsolr (>= 1.0.6, < 3) - twitter-typeahead-rails (= 0.11.1.pre.corejavascript) - blacklight-access_controls (0.6.2) - blacklight (~> 6.0) - cancancan (~> 1.8) + ostruct (>= 0.3.2) + rails (>= 5.1, < 7.2) + view_component (>= 2.66, < 4) + blacklight-access_controls (6.0.1) + blacklight (> 6.0, < 8) + cancancan (>= 1.8) deprecation (~> 1.0) - blacklight-gallery (0.12.0) - blacklight (~> 6.3) - bootstrap-sass (~> 3.0) - openseadragon (>= 0.2.0) - rails - blacklight_iiif_search (1.0.0) - blacklight (~> 6.0) + blacklight-gallery (4.4.0) + blacklight (>= 7.17, < 9) + rails (>= 6.1, < 8) + blacklight_advanced_search (7.0.0) + blacklight (~> 7.0) + parslet + blacklight_iiif_search (2.0.0) + blacklight (~> 7.0) iiif-presentation - rails (>= 4.2, < 6) - blacklight_oai_provider (6.1.1) - blacklight (~> 6.0) - oai (~> 1.0) - bolognese (1.11.0) + rails (>= 5.1, < 7) + blacklight_oai_provider (7.0.2) + blacklight (~> 7.0) + oai (~> 1.2) + rexml + blacklight_range_limit (8.4.0) + blacklight (>= 7.25.2, < 9) + deprecation + view_component (>= 2.54, < 4) + bolognese (1.11.5) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) bibtex-ruby (>= 5.1.0) @@ -242,27 +336,27 @@ GEM rdf-rdfxml (~> 3.1) rdf-turtle (~> 3.1) thor (>= 0.19) - bootstrap-datepicker-rails (1.9.0.1) + bootstrap (4.6.2) + autoprefixer-rails (>= 9.1.0) + popper_js (>= 1.16.1, < 2) + sassc-rails (>= 2.0.0) + bootstrap-datepicker-rails (1.10.0.1) railties (>= 3.0) - bootstrap-sass (3.4.1) - autoprefixer-rails (>= 5.2.1) - sassc (>= 2.0.0) breadcrumbs_on_rails (3.0.1) - browse-everything (1.2.0) + browse-everything (1.3.0) addressable (~> 2.5) aws-sdk-s3 dropbox_api (>= 0.1.20) google-apis-drive_v3 googleauth (>= 0.6.6, < 2.0) - rails (>= 4.2, < 7.1) + rails (>= 4.2, < 7.2) ruby-box signet (~> 0.8) typhoeus builder (3.2.4) - bulkrax (5.4.0) + bulkrax (5.5.0) bagit (~> 0.4) coderay - dry-monads (~> 1.4.0) iso8601 (~> 0.9.0) kaminari language_list (~> 1.2, >= 1.2.1) @@ -275,8 +369,8 @@ GEM rubyzip simple_form byebug (11.1.3) - cancancan (1.17.0) - capybara (3.39.0) + cancancan (3.5.0) + capybara (3.39.2) addressable matrix mini_mime (>= 0.1.3) @@ -288,7 +382,7 @@ GEM capybara-screenshot (1.0.26) capybara (>= 1.0, < 4) launchy - carrierwave (1.3.3) + carrierwave (1.3.4) activemodel (>= 4.0.0) activesupport (>= 4.0.0) mime-types (>= 1.16) @@ -303,8 +397,7 @@ GEM csl (~> 1.6) clipboard-rails (1.7.1) cocoon (1.2.15) - codemirror-rails (5.16.0) - railties (>= 3.0, < 6.0) + codemirror-rails (0.3.1) coderay (1.1.3) coffee-rails (4.2.2) coffee-script (>= 2.2.0) @@ -315,7 +408,7 @@ GEM coffee-script-source (1.12.2) colorize (0.8.1) concurrent-ruby (1.2.2) - connection_pool (2.4.0) + connection_pool (2.4.1) crack (0.4.5) rexml crass (1.0.6) @@ -330,14 +423,11 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - date (3.3.3) + date (3.3.4) declarative (0.0.20) - declarative-builder (0.1.0) - declarative-option (< 0.2.0) - declarative-option (0.1.0) deprecation (1.1.0) activesupport - derivative-rodeo (0.5.0) + derivative-rodeo (0.5.3) activesupport (>= 5) aws-sdk-s3 aws-sdk-sqs @@ -346,7 +436,7 @@ GEM mime-types mini_magick nokogiri - devise (4.9.2) + devise (4.9.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) @@ -354,18 +444,15 @@ GEM warden (~> 1.2.3) devise-guests (0.8.1) devise - devise-i18n (1.11.0) + devise-i18n (1.12.0) devise (>= 4.9.0) - devise_invitable (1.7.5) - actionmailer (>= 4.1.0) - devise (>= 4.0.0) + devise_invitable (2.0.9) + actionmailer (>= 5.0) + devise (>= 4.6) diff-lcs (1.5.0) - disposable (0.4.7) + disposable (0.6.3) declarative (>= 0.0.9, < 1.0.0) - declarative-builder (< 0.2.0) - declarative-option (< 0.2.0) - representable (>= 2.4.0, <= 3.1.0) - uber (< 0.2.0) + representable (>= 3.1.1, < 4) docile (1.4.0) docopt (0.5.0) draper (4.0.2) @@ -378,108 +465,122 @@ GEM dropbox_api (0.1.21) faraday (< 3.0) oauth2 (~> 1.1) - dry-configurable (0.16.1) - dry-core (~> 0.6) + dry-configurable (1.1.0) + dry-core (~> 1.0, < 2) zeitwerk (~> 2.6) dry-container (0.11.0) concurrent-ruby (~> 1.0) - dry-core (0.9.1) + dry-core (1.0.1) concurrent-ruby (~> 1.0) zeitwerk (~> 2.6) - dry-equalizer (0.3.0) - dry-events (0.2.0) + dry-events (1.0.1) concurrent-ruby (~> 1.0) - dry-core (~> 0.4) - dry-equalizer (~> 0.2) - dry-inflector (0.3.0) + dry-core (~> 1.0, < 2) + dry-inflector (1.0.0) dry-initializer (3.1.1) - dry-logic (1.3.0) + dry-logic (1.5.0) concurrent-ruby (~> 1.0) - dry-core (~> 0.9, >= 0.9) + dry-core (~> 1.0, < 2) zeitwerk (~> 2.6) - dry-matcher (0.9.0) - dry-core (~> 0.4, >= 0.4.8) - dry-monads (1.4.0) + dry-monads (1.6.0) concurrent-ruby (~> 1.0) - dry-core (~> 0.7) - dry-schema (1.11.3) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.3) concurrent-ruby (~> 1.0) - dry-configurable (~> 0.16, >= 0.16) - dry-core (~> 0.9, >= 0.9) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) dry-initializer (~> 3.0) - dry-logic (~> 1.3) - dry-types (~> 1.6) + dry-logic (>= 1.4, < 2) + dry-types (>= 1.7, < 2) zeitwerk (~> 2.6) - dry-struct (1.5.2) - dry-core (~> 0.9, >= 0.9) - dry-types (~> 1.6) + dry-struct (1.6.0) + dry-core (~> 1.0, < 2) + dry-types (>= 1.7, < 2) ice_nine (~> 0.11) zeitwerk (~> 2.6) - dry-transaction (0.13.3) - dry-container (>= 0.2.8) - dry-events (>= 0.1.0) - dry-matcher (>= 0.7.0) - dry-monads (>= 0.4.0) - dry-types (1.6.1) + dry-types (1.7.1) concurrent-ruby (~> 1.0) - dry-container (~> 0.3) - dry-core (~> 0.9, >= 0.9) - dry-inflector (~> 0.1, >= 0.1.2) - dry-logic (~> 1.3, >= 1.3) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) zeitwerk (~> 2.6) - dry-validation (1.9.0) + dry-validation (1.10.0) concurrent-ruby (~> 1.0) - dry-container (~> 0.7, >= 0.7.1) - dry-core (~> 0.9, >= 0.9) + dry-core (~> 1.0, < 2) dry-initializer (~> 3.0) - dry-schema (~> 1.11, >= 1.11.0) + dry-schema (>= 1.12, < 2) zeitwerk (~> 2.6) easy_translate (0.5.1) thread thread_safe - ebnf (2.2.1) - amazing_print (~> 1.2) + ebnf (2.4.0) htmlentities (~> 4.3) - rdf (~> 3.1) + rdf (~> 3.3) scanf (~> 1.0) - sxp (~> 1.1) - unicode-types (~> 1.6) + sxp (~> 1.3) + unicode-types (~> 1.8) edtf (3.1.1) activesupport (>= 3.0, < 8.0) - equivalent-xml (0.6.0) - nokogiri (>= 1.4.3) erubi (1.12.0) + et-orbi (1.2.7) + tzinfo ethon (0.16.0) ffi (>= 1.15.0) excon (0.71.1) - execjs (2.8.1) - factory_bot (6.2.1) + execjs (2.9.1) + factory_bot (6.4.2) activesupport (>= 5.0.0) - factory_bot_rails (6.2.0) - factory_bot (~> 6.2.0) + factory_bot_rails (6.4.2) + factory_bot (~> 6.4) railties (>= 5.0.0) - faraday (0.17.6) - multipart-post (>= 1.2, < 3) + faraday (2.7.12) + base64 + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) faraday-encoding (0.0.5) faraday - faraday_middleware (0.14.0) - faraday (>= 0.7.4, < 1.0) + faraday-excon (2.1.0) + excon (>= 0.27.4) + faraday (~> 2.0) + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) + faraday-gzip (0.1.0) + faraday (>= 1.0) + zlib (~> 2.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (3.0.2) fcrepo_wrapper (0.9.0) ruby-progressbar - ffi (1.15.5) - flipflop (2.6.0) + ffi (1.16.3) + flipflop (2.7.1) activesupport (>= 4.0) + terminal-table (>= 1.8) flot-rails (0.0.7) jquery-rails flutie (2.2.0) font-awesome-rails (4.7.0.8) railties (>= 3.2, < 8.0) + fugit (1.9.0) + et-orbi (~> 1, >= 1.2.7) + raabro (~> 1.4) gender_detector (0.1.2) unicode_utils (>= 1.3.0) - geocoder (1.8.1) - globalid (1.1.0) - activesupport (>= 5.0) - google-apis-core (0.11.0) + geo_coord (0.2.0) + geocoder (1.8.2) + globalid (1.2.1) + activesupport (>= 6.1) + good_job (2.99.0) + activejob (>= 5.2.0) + activerecord (>= 5.2.0) + concurrent-ruby (>= 1.0.2) + fugit (>= 1.1) + railties (>= 5.2.0) + thor (>= 0.14.1) + webrick (>= 1.3) + zeitwerk (>= 2.0) + google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -488,17 +589,17 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-drive_v3 (0.39.0) + google-apis-drive_v3 (0.46.0) google-apis-core (>= 0.11.0, < 2.a) - googleauth (1.5.2) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) - haml (5.2.2) - temple (>= 0.8.0) + haml (6.3.0) + temple (>= 0.8.2) + thor tilt hamster (3.0.0) concurrent-ruby (~> 1.0) @@ -506,46 +607,46 @@ GEM hashie (5.0.0) highline (2.1.0) hiredis (0.6.3) - html_tokenizer (0.0.7) htmlentities (4.3.4) http_logger (0.7.0) httparty (0.21.0) mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - hydra-access-controls (11.0.7) + hydra-access-controls (12.1.0) active-fedora (>= 10.0.0) - activesupport (>= 4, < 6) - blacklight (>= 5.16) - blacklight-access_controls (~> 0.6.0) - cancancan (~> 1.8) + activesupport (>= 5.2, < 7.1) + blacklight-access_controls (~> 6.0) + cancancan (>= 1.8, < 4) deprecation (~> 1.0) - hydra-core (11.0.7) - hydra-access-controls (= 11.0.7) - railties (>= 4.0.0, < 6) - hydra-derivatives (3.7.0) - active-fedora (>= 11.5.6, != 13.2.1, != 13.2.0, != 13.1.3, != 13.1.2, != 13.1.1, != 13.1.0, != 13.0.0, != 12.2.1, != 12.2.0, != 12.1.1, != 12.1.0, != 12.0.3, != 12.0.2, != 12.0.1, != 12.0.0) + hydra-core (12.1.0) + hydra-access-controls (= 12.1.0) + railties (>= 5.2, < 7.1) + hydra-derivatives (3.8.0) + active-fedora (>= 14.0) + active-triples (>= 1.2) active_encode (~> 0.1) - activesupport (>= 4.0, < 7) + activesupport (>= 4.0, < 7.1) addressable (~> 2.5) deprecation mime-types (> 2.0, < 4.0) mini_magick (>= 3.2, < 5) - hydra-editor (5.0.5) + hydra-editor (6.2.0) active-fedora (>= 9.0.0) - activerecord (~> 5.0) + activerecord (>= 5.2, < 7.1) almond-rails (~> 0.1) - cancancan (~> 1.8) - rails (>= 5, < 6) - simple_form (>= 4.1.0, < 6.0) - sprockets (~> 3.7) + cancancan + psych (~> 3.3, < 4) + rails (>= 5.2, < 7.1) + simple_form (>= 4.1.0, < 5.2) + sprockets (>= 3.7) sprockets-es6 - hydra-file_characterization (1.1.2) + hydra-file_characterization (1.2.0) activesupport (>= 3.0.0) - hydra-head (11.0.7) - hydra-access-controls (= 11.0.7) - hydra-core (= 11.0.7) - rails (>= 5.2, < 6.1) + hydra-head (12.1.0) + hydra-access-controls (= 12.1.0) + hydra-core (= 12.1.0) + rails (>= 5.2, < 7.1) hydra-pcdm (1.3.0) active-fedora (>= 10, < 15) mime-types (>= 1) @@ -555,64 +656,6 @@ GEM hydra-derivatives (~> 3.6) hydra-file_characterization (~> 1.0) hydra-pcdm (>= 0.9) - hyrax (3.5.0) - active-fedora (~> 13.1, >= 13.1.2) - almond-rails (~> 0.1) - awesome_nested_set (~> 3.1) - blacklight (~> 6.14) - blacklight-gallery (~> 0.7) - breadcrumbs_on_rails (~> 3.0) - browse-everything (>= 0.16, < 2.0) - carrierwave (~> 1.0) - clipboard-rails (~> 1.5) - draper (~> 4.0) - dry-equalizer (~> 0.2) - dry-events (~> 0.2.0) - dry-monads (< 1.5) - dry-struct (~> 1.0) - dry-transaction (~> 0.11) - dry-validation (~> 1.3) - flipflop (~> 2.3) - flot-rails (~> 0.0.6) - font-awesome-rails (~> 4.2) - hydra-derivatives (~> 3.3) - hydra-editor (~> 5.0, >= 5.0.4) - hydra-file_characterization (~> 1.1.2) - hydra-head (~> 11.0, >= 11.0.1) - hydra-works (>= 0.16) - iiif_manifest (>= 0.3, < 2.0) - jquery-datatables-rails (~> 3.4) - jquery-ui-rails (~> 6.0) - json-ld (< 3.2) - json-schema - kaminari_route_prefix (~> 0.1.1) - legato (~> 0.3) - linkeddata - mailboxer (~> 0.12) - nest (~> 3.1) - noid-rails (~> 3.0.0) - oauth - oauth2 (~> 1.2) - posix-spawn - power_converter (~> 0.1, >= 0.1.2) - psych (~> 3.3) - qa (~> 5.5, >= 5.5.1) - rails (~> 5.0) - rails_autolink (~> 1.1) - rdf-rdfxml - rdf-vocab (~> 3.0) - redis (~> 4.0) - redis-namespace (~> 1.5) - redlock (>= 0.1.2) - reform (~> 2.3) - reform-rails (~> 0.2.0) - retriable (>= 2.9, < 4.0) - samvera-nesting_indexer (~> 2.0) - sass-rails (~> 5.0) - select2-rails (~> 3.5) - signet - tinymce-rails (~> 5.10) - valkyrie (~> 2, >= 2.1.1) i18n (1.14.1) concurrent-ruby (~> 1.0) i18n-debug (1.2.0) @@ -629,9 +672,12 @@ GEM rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) ice_nine (0.11.2) - iiif-presentation (1.1.0) + iiif-image-api (0.2.0) + activesupport + iiif-presentation (1.3.0) activesupport (>= 3.2.18) - faraday (>= 0.9) + faraday (~> 2.7) + geo_coord json iiif_manifest (1.3.1) activesupport (>= 4) @@ -641,40 +687,34 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) jmespath (1.6.2) - jquery-datatables-rails (3.4.0) - actionpack (>= 3.1) - jquery-rails - railties (>= 3.1) - sass-rails - jquery-rails (4.5.1) + jquery-rails (4.6.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jquery-ui-rails (6.0.1) - railties (>= 3.2.16) - json (2.6.3) + json (2.7.1) json-canonicalization (0.3.1) - json-jwt (1.15.3) + json-jwt (1.16.3) activesupport (>= 4.2) aes_key_wrap bindata - httpclient - json-ld (3.1.10) + faraday (~> 2.0) + faraday-follow_redirects + json-ld (3.2.4) htmlentities (~> 4.3) - json-canonicalization (~> 0.2) + json-canonicalization (~> 0.3) link_header (~> 0.0, >= 0.0.8) - multi_json (~> 1.14) - rack (~> 2.0) - rdf (~> 3.1) - json-ld-preloaded (3.1.6) - json-ld (~> 3.1) - rdf (~> 3.1) - json-schema (4.0.0) + multi_json (~> 1.15) + rack (>= 2.2, < 4) + rdf (~> 3.2, >= 3.2.10) + json-ld-preloaded (3.2.2) + json-ld (~> 3.2) + rdf (~> 3.2) + json-schema (4.1.1) addressable (>= 2.8) jsonlint (0.3.0) oj (~> 3) optimist (~> 3) - jwt (2.7.0) + jwt (2.7.1) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -687,25 +727,24 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - kaminari_route_prefix (0.1.1) - kaminari (~> 1.0) language_list (1.2.1) latex-decode (0.4.0) launchy (2.5.2) addressable (~> 2.8) - ld-patch (3.1.3) - ebnf (~> 2.1) - rdf (~> 3.1) - rdf-xsd (~> 3.1) - sparql (~> 3.1) - sxp (~> 1.1) - ldp (1.0.3) + ld-patch (3.3.0) + ebnf (~> 2.4) + rdf (~> 3.3) + rdf-xsd (~> 3.3) + sparql (~> 3.3) + sxp (~> 1.3) + ldp (1.2.0) deprecation - faraday + faraday (>= 1) http_logger - json-ld - rdf (>= 1.1) + json-ld (~> 3.2) + rdf (~> 3.2) rdf-isomorphic + rdf-ldp rdf-turtle rdf-vocab (>= 0.8) slop @@ -718,44 +757,44 @@ GEM multi_json libxml-ruby (3.2.4) link_header (0.0.8) - linkeddata (3.1.6) - equivalent-xml (~> 0.6) - json-ld (~> 3.1, >= 3.1.10) - json-ld-preloaded (~> 3.1, >= 3.1.6) - ld-patch (~> 3.1, >= 3.1.3) - nokogiri (~> 1.12) - rdf (~> 3.1, >= 3.1.15) - rdf-aggregate-repo (~> 3.1) - rdf-isomorphic (~> 3.1, >= 3.1.1) - rdf-json (~> 3.1) - rdf-microdata (~> 3.1, >= 3.1.4) - rdf-n3 (~> 3.1, >= 3.1.2) - rdf-normalize (~> 0.4) - rdf-ordered-repo (~> 3.1, >= 3.1.1) - rdf-rdfa (~> 3.1, >= 3.1.3) - rdf-rdfxml (~> 3.1, >= 3.1.1) - rdf-reasoner (~> 0.7, >= 0.7.2) - rdf-tabular (~> 3.1, >= 3.1.1) - rdf-trig (~> 3.1, >= 3.1.2) - rdf-trix (~> 3.1, >= 3.1.1) - rdf-turtle (~> 3.1, >= 3.1.3) - rdf-vocab (~> 3.1, >= 3.1.14) - rdf-xsd (~> 3.1, >= 3.1.1) - shacl (~> 0.1, >= 0.1.1) - shex (~> 0.6, >= 0.6.4) - sparql (~> 3.1, >= 3.1.8) - sparql-client (~> 3.1, >= 3.1.2) - listen (3.1.5) + linkeddata (3.2.1) + json-ld (~> 3.2, >= 3.2.3) + json-ld-preloaded (~> 3.2) + ld-patch (~> 3.2) + nokogiri (~> 1.13, >= 1.13.8) + rdf (~> 3.2, >= 3.2.9) + rdf-aggregate-repo (~> 3.2, >= 3.2.1) + rdf-hamster-repo (~> 3.2) + rdf-isomorphic (~> 3.2, >= 3.2.1) + rdf-json (~> 3.2) + rdf-microdata (~> 3.2, >= 3.2.1) + rdf-n3 (~> 3.2, >= 3.2.1) + rdf-normalize (~> 0.5) + rdf-ordered-repo (~> 3.2, >= 3.2.1) + rdf-rdfa (~> 3.2) + rdf-rdfxml (~> 3.2) + rdf-reasoner (~> 0.8) + rdf-tabular (~> 3.2, >= 3.2.1) + rdf-trig (~> 3.2) + rdf-trix (~> 3.2) + rdf-turtle (~> 3.2, >= 3.2.1) + rdf-vocab (~> 3.2, >= 3.2.1) + rdf-xsd (~> 3.2, >= 3.2.1) + shacl (~> 0.2, >= 0.2.1) + shex (~> 0.7, >= 0.7.1) + sparql (~> 3.2, >= 3.2.4) + sparql-client (~> 3.2, >= 3.2.1) + yaml-ld (~> 0.0) + listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - logger (1.5.3) - lograge (0.12.0) + logger (1.6.0) + lograge (0.14.0) actionpack (>= 4) activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.21.3) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -767,27 +806,29 @@ GEM carrierwave (>= 0.5.8) rails (>= 5.0.0) marcel (1.0.2) - maremma (4.9.8) + maremma (4.9.9) activesupport (>= 4.2.5) addressable (>= 2.3.6) builder (~> 3.2, >= 3.2.2) excon (~> 0.71.0) - faraday (~> 0.17.3) - faraday-encoding (~> 0.0.4) - faraday_middleware (~> 0.14.0) - nokogiri (>= 1.11.2, < 1.14.0) + faraday (>= 2.0) + faraday-encoding (~> 0.0.5) + faraday-excon (~> 2.1.0) + faraday-follow_redirects (~> 0.3.0) + faraday-gzip (~> 0.1.0) + faraday-multipart (~> 1.0.4) + nokogiri (>= 1.13.1, < 1.14.0) oj (>= 2.8.3) oj_mimic_json (~> 1.0, >= 1.0.1) matrix (0.4.2) - memoist (0.16.2) method_source (1.0.0) - mime-types (3.4.1) + mime-types (3.5.1) mime-types-data (~> 3.2015) - mime-types-data (3.2023.0218.1) + mime-types-data (3.2023.1205) mini_magick (4.12.0) - mini_mime (1.1.2) - mini_portile2 (2.8.4) - minitest (5.18.1) + mini_mime (1.1.5) + mini_portile2 (2.8.5) + minitest (5.20.0) mods (2.4.1) edtf iso-639 @@ -804,19 +845,19 @@ GEM redic net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.3.6) + net-imap (0.4.8) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.4.0) net-protocol - nio4r (2.5.9) + nio4r (2.7.0) noid (0.9.0) - noid-rails (3.0.3) - actionpack (>= 5.0.0, < 7) + noid-rails (3.1.0) + actionpack (>= 5.0.0, < 7.1) noid (~> 0.9) nokogiri (1.13.10) mini_portile2 (~> 2.8.0) @@ -824,10 +865,10 @@ GEM nom-xml (1.2.0) i18n nokogiri - oai (1.1.0) + oai (1.2.1) builder (>= 3.1.0) - faraday - faraday_middleware + faraday (< 3) + faraday-follow_redirects (>= 0.3.0, < 2) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) snaky_hash (~> 2.0) @@ -840,9 +881,10 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 4) - oj (3.14.3) + oj (3.16.3) + bigdecimal (>= 3.0) oj_mimic_json (1.0.1) - okcomputer (1.18.4) + okcomputer (1.18.5) omniauth (2.1.1) hashie (>= 3.4.6) rack (>= 2.2.3) @@ -855,37 +897,42 @@ GEM omniauth-saml (2.1.0) omniauth (~> 2.0) ruby-saml (~> 1.12) - omniauth_openid_connect (0.6.1) + omniauth_openid_connect (0.7.1) omniauth (>= 1.9, < 3) - openid_connect (~> 1.1) - openid_connect (1.4.2) + openid_connect (~> 2.2) + openid_connect (2.2.0) activemodel attr_required (>= 1.0.0) - json-jwt (>= 1.15.0) + faraday (~> 2.0) + faraday-follow_redirects + json-jwt (>= 1.16) net-smtp - rack-oauth2 (~> 1.21) - swd (~> 1.3) + rack-oauth2 (~> 2.2) + swd (~> 2.0) tzinfo validate_email validate_url - webfinger (~> 1.2) + webfinger (~> 2.0) openseadragon (0.6.0) rails (> 3.2.0) - optimist (3.0.1) + optimist (3.1.0) + order_already (0.3.1) + rails-html-sanitizer (~> 1.4) orm_adapter (0.5.0) os (1.1.4) + ostruct (0.6.0) parallel (1.23.0) - parser (2.5.3.0) - ast (~> 2.4.0) + parser (3.2.2.4) + ast (~> 2.4.1) + racc parslet (2.0.0) - pg (1.5.3) + pg (1.5.4) + popper_js (1.16.1) posix-spawn (0.3.15) postrank-uri (1.1) addressable (>= 2.4.0) nokogiri (>= 1.8.0) public_suffix (>= 4.0.0, < 5) - power_converter (0.1.2) - powerpack (0.1.3) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) @@ -896,158 +943,169 @@ GEM public_suffix (4.0.7) puma (5.6.7) nio4r (~> 2.0) - qa (5.10.0) + qa (5.11.0) activerecord-import deprecation faraday (< 3.0, != 2.0.0) geocoder ldpath nokogiri (~> 1.6) - rails (>= 5.0, < 7.1) + rails (>= 5.0, < 7.2) rdf - racc (1.7.1) + raabro (1.4.0) + racc (1.7.3) rack (2.2.8) - rack-oauth2 (1.21.3) + rack-oauth2 (2.2.0) activesupport attr_required - httpclient + faraday (~> 2.0) + faraday-follow_redirects json-jwt (>= 1.11.0) rack (>= 2.1.0) - rack-protection (3.0.6) - rack + rack-protection (3.1.0) + rack (~> 2.2, >= 2.2.4) rack-test (0.7.0) rack (>= 1.0, < 3) - rails (5.2.8.1) - actioncable (= 5.2.8.1) - actionmailer (= 5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) - activemodel (= 5.2.8.1) - activerecord (= 5.2.8.1) - activestorage (= 5.2.8.1) - activesupport (= 5.2.8.1) - bundler (>= 1.3.0) - railties (= 5.2.8.1) + rails (6.1.7.6) + actioncable (= 6.1.7.6) + actionmailbox (= 6.1.7.6) + actionmailer (= 6.1.7.6) + actionpack (= 6.1.7.6) + actiontext (= 6.1.7.6) + actionview (= 6.1.7.6) + activejob (= 6.1.7.6) + activemodel (= 6.1.7.6) + activerecord (= 6.1.7.6) + activestorage (= 6.1.7.6) + activesupport (= 6.1.7.6) + bundler (>= 1.15.0) + railties (= 6.1.7.6) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) activesupport (>= 5.0.1.rc1) - rails-dom-testing (2.1.1) + rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) rails-html-sanitizer (1.5.0) loofah (~> 2.19, >= 2.19.1) - rails-i18n (5.1.3) + rails-i18n (7.0.8) i18n (>= 0.7, < 2) - railties (>= 5.0, < 6) + railties (>= 6.0.0, < 8) rails_autolink (1.1.8) actionview (> 3.1) activesupport (> 3.1) railties (> 3.1) - railties (5.2.8.1) - actionpack (= 5.2.8.1) - activesupport (= 5.2.8.1) + railties (6.1.7.6) + actionpack (= 6.1.7.6) + activesupport (= 6.1.7.6) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + rake (>= 12.2) + thor (~> 1.0) rainbow (3.1.1) - rake (13.0.6) + rake (13.1.0) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rdf (3.1.15) - hamster (~> 3.0) + rdf (3.3.1) + bcp47_spec (~> 0.2) link_header (~> 0.0, >= 0.0.8) - rdf-aggregate-repo (3.1.0) - rdf (~> 3.1) - rdf-isomorphic (3.1.1) - rdf (~> 3.1) - rdf-json (3.1.0) - rdf (~> 3.1) - rdf-microdata (3.1.4) + rdf-aggregate-repo (3.3.0) + rdf (~> 3.3) + rdf-hamster-repo (3.3.0) + hamster (~> 3.0) + rdf (~> 3.3) + rdf-isomorphic (3.3.0) + rdf (~> 3.3) + rdf-json (3.3.0) + rdf (~> 3.3) + rdf-ldp (0.1.0) + deprecation + rdf + rdf-microdata (3.2.1) htmlentities (~> 4.3) - nokogiri (~> 1.12) - rdf (~> 3.1, >= 3.1.13) - rdf-rdfa (~> 3.1, >= 3.1.3) - rdf-xsd (~> 3.1) - rdf-n3 (3.1.2) - ebnf (~> 2.1) - rdf (~> 3.1, >= 3.1.8) - sparql (~> 3.1, >= 3.1.4) - sxp (~> 1.1) - rdf-normalize (0.4.0) - rdf (~> 3.1) - rdf-ordered-repo (3.1.1) - rdf (~> 3.1) - rdf-rdfa (3.1.3) - haml (~> 5.2) + nokogiri (~> 1.13) + rdf (~> 3.2) + rdf-rdfa (~> 3.2) + rdf-xsd (~> 3.2) + rdf-n3 (3.3.0) + ebnf (~> 2.4) + rdf (~> 3.3) + sparql (~> 3.3) + sxp (~> 1.3) + rdf-normalize (0.7.0) + rdf (~> 3.3) + rdf-ordered-repo (3.3.0) + rdf (~> 3.3) + rdf-rdfa (3.3.0) + haml (~> 6.1) htmlentities (~> 4.3) - rdf (~> 3.1, >= 3.1.13) - rdf-aggregate-repo (~> 3.1) - rdf-vocab (~> 3.1, >= 3.1.11) - rdf-xsd (~> 3.1) - rdf-rdfxml (3.1.1) + rdf (~> 3.3) + rdf-aggregate-repo (~> 3.3) + rdf-vocab (~> 3.3) + rdf-xsd (~> 3.3) + rdf-rdfxml (3.3.0) + builder (~> 3.2, >= 3.2.4) htmlentities (~> 4.3) - rdf (~> 3.1) - rdf-rdfa (~> 3.1) - rdf-xsd (~> 3.1) - rdf-reasoner (0.7.2) - rdf (~> 3.1, >= 3.1.12) - rdf-xsd (~> 3.1) - rdf-tabular (3.1.1) - addressable (~> 2.3) + rdf (~> 3.3) + rdf-xsd (~> 3.3) + rdf-reasoner (0.9.0) + rdf (~> 3.3) + rdf-xsd (~> 3.3) + rdf-tabular (3.2.1) + addressable (~> 2.8) bcp47 (~> 0.3, >= 0.3.3) - json-ld (~> 3.1) - rdf (~> 3.1) - rdf-vocab (~> 3.1) - rdf-xsd (~> 3.1) - rdf-trig (3.1.2) - ebnf (~> 2.1) - rdf (~> 3.1) - rdf-turtle (~> 3.1) - rdf-trix (3.1.1) - rdf (~> 3.1) - rdf-xsd (~> 3.1) - rdf-turtle (3.1.3) - ebnf (~> 2.1) - rdf (~> 3.1, >= 3.1.8) - rdf-vocab (3.1.14) - rdf (~> 3.1, >= 3.1.12) - rdf-xsd (3.1.1) - rdf (~> 3.1) + json-ld (~> 3.2) + rdf (~> 3.2, >= 3.2.7) + rdf-vocab (~> 3.2) + rdf-xsd (~> 3.2) + rdf-trig (3.3.0) + ebnf (~> 2.4) + rdf (~> 3.3) + rdf-turtle (~> 3.3) + rdf-trix (3.3.0) + rdf (~> 3.3) + rdf-xsd (~> 3.3) + rdf-turtle (3.3.0) + ebnf (~> 2.4) + rdf (~> 3.3) + rdf-vocab (3.3.0) + rdf (~> 3.3) + rdf-xsd (3.3.0) + rdf (~> 3.3) rexml (~> 3.2) redic (1.5.3) hiredis redis (4.8.1) - redis-namespace (1.10.0) + redis-namespace (1.11.0) redis (>= 4) redlock (1.3.2) redis (>= 3.0.0, < 6.0) - reform (2.5.0) - disposable (>= 0.4.2, < 0.5.0) - representable (>= 2.4.0, < 3.1.0) + reform (2.6.2) + disposable (>= 0.5.0, < 1.0.0) + representable (>= 3.1.1, < 4) uber (< 0.2.0) - reform-rails (0.2.3) + reform-rails (0.2.6) activemodel (>= 5.0) reform (>= 2.3.1, < 3.0.0) - regexp_parser (2.8.0) - representable (3.0.4) + regexp_parser (2.8.3) + representable (3.2.0) declarative (< 0.1.0) - declarative-option (< 0.2.0) + trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) request_store (1.5.1) rack (>= 1.4) - responders (3.1.0) + responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) retriable (3.1.2) - rexml (3.2.5) - riiif (1.7.1) + rexml (3.2.6) + riiif (2.4.0) deprecation (>= 1.0.0) - railties (>= 4.2, < 6) + iiif-image-api (>= 0.1.0) + railties (>= 4.2, < 8) rolify (6.0.1) rsolr (2.5.0) builder (>= 2.1.2) @@ -1056,7 +1114,7 @@ GEM rspec-core (~> 3.12.0) rspec-expectations (~> 3.12.0) rspec-mocks (~> 3.12.0) - rspec-activemodel-mocks (1.1.0) + rspec-activemodel-mocks (1.2.0) activemodel (>= 3.0) activesupport (>= 3.0) rspec-mocks (>= 2.99, < 4.0) @@ -1068,29 +1126,40 @@ GEM rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.12.5) + rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-rails (5.1.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - railties (>= 5.2) - rspec-core (~> 3.10) - rspec-expectations (~> 3.10) - rspec-mocks (~> 3.10) - rspec-support (~> 3.10) + rspec-rails (6.1.0) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) rspec-retry (0.6.2) rspec-core (> 3.3) - rspec-support (3.12.0) + rspec-support (3.12.1) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (0.52.1) + rubocop (1.28.2) parallel (~> 1.10) - parser (>= 2.4.0.2, < 3.0) - powerpack (~> 0.1) + parser (>= 3.1.0.0) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.17.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.30.0) + parser (>= 3.2.1.0) + rubocop-performance (1.19.1) + rubocop (>= 1.7.0, < 2.0) + rubocop-ast (>= 0.4.0) + rubocop-rails (2.15.2) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.7.0, < 2.0) rubocop-rspec (1.22.2) rubocop (>= 0.52.1) ruby-box (1.15.0) @@ -1099,27 +1168,26 @@ GEM multipart-post oauth2 ruby-progressbar (1.13.0) - ruby-saml (1.15.0) + ruby-saml (1.16.0) nokogiri (>= 1.13.10) rexml ruby2_keywords (0.0.5) - ruby_dep (1.5.0) rubyzip (2.3.2) - samvera-nesting_indexer (2.0.0) - dry-equalizer sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.1.0) - railties (>= 5.2.0) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (>= 1.1, < 3) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt scanf (1.0.0) scss_lint (0.60.0) sass (~> 3.5, >= 3.5.5) @@ -1129,34 +1197,32 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sentry-raven (2.13.0) - faraday (>= 0.7.6, < 1.0) - shacl (0.1.1) - json-ld (~> 3.1, >= 3.1.7) - rdf (~> 3.1, >= 3.1.8) - sparql (~> 3.1) - sxp (~> 1.1) - shex (0.6.4) - ebnf (~> 2.1, >= 2.2) + shacl (0.3.0) + json-ld (~> 3.2) + rdf (~> 3.2, >= 3.2.8) + sparql (~> 3.2, >= 3.2.4) + sxp (~> 1.2) + shex (0.7.1) + ebnf (~> 2.2) htmlentities (~> 4.3) - json-ld (~> 3.1) - json-ld-preloaded (~> 3.1) - rdf (~> 3.1) - rdf-xsd (~> 3.1) - sparql (~> 3.1) - sxp (~> 1.1) + json-ld (~> 3.2) + json-ld-preloaded (~> 3.2) + rdf (~> 3.2) + rdf-xsd (~> 3.2) + sparql (~> 3.2) + sxp (~> 1.2) shoulda-matchers (4.5.1) activesupport (>= 4.2.0) - sidekiq (6.5.9) + sidekiq (6.5.12) connection_pool (>= 2.2.5, < 3) rack (~> 2.0) redis (>= 4.5.0, < 5) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simple_form (5.2.0) + simple_form (5.1.0) actionpack (>= 5.2) activemodel (>= 5.2) simplecov (0.22.0) @@ -1175,18 +1241,18 @@ GEM retriable ruby-progressbar rubyzip - sparql (3.1.8) - builder (~> 3.2) - ebnf (~> 2.1) - logger (~> 1.4) - rdf (~> 3.1, >= 3.1.14) - rdf-aggregate-repo (~> 3.1) - rdf-xsd (~> 3.1) - sparql-client (~> 3.1, >= 3.1.2) - sxp (~> 1.1) - sparql-client (3.1.2) - net-http-persistent (~> 4.0, >= 4.0.1) - rdf (~> 3.1) + sparql (3.3.0) + builder (~> 3.2, >= 3.2.4) + ebnf (~> 2.4) + logger (~> 1.5) + rdf (~> 3.3) + rdf-aggregate-repo (~> 3.3) + rdf-xsd (~> 3.3) + sparql-client (~> 3.3) + sxp (~> 1.3) + sparql-client (3.3.0) + net-http-persistent (~> 4.0, >= 4.0.2) + rdf (~> 3.3) spring (1.7.2) spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) @@ -1203,26 +1269,29 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) ssrf_filter (1.0.8) - swd (1.3.0) + swd (2.0.2) activesupport (>= 3) attr_required (>= 0.0.5) - httpclient (>= 2.4) - sxp (1.1.0) - rdf (~> 3.1) - temple (0.10.0) + faraday (~> 2.0) + faraday-follow_redirects + sxp (1.3.0) + matrix (~> 0.4) + rdf (~> 3.3) + temple (0.10.3) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - terser (1.1.14) + terser (1.1.20) execjs (>= 0.3.0, < 3) tether-rails (1.4.0) rails (>= 3.1) - thor (1.2.2) + thor (1.3.0) thread (0.2.2) thread_safe (0.3.6) - tilt (2.1.0) - timeout (0.4.0) - tinymce-rails (5.10.7) + tilt (2.3.0) + timeout (0.4.1) + tinymce-rails (5.10.9) railties (>= 3.1.1) + trailblazer-option (0.1.2) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -1230,13 +1299,13 @@ GEM actionpack (>= 3.1) jquery-rails railties (>= 3.1) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) - tzinfo (1.2.11) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) uber (0.1.0) unicode-display_width (1.8.0) - unicode-types (1.8.0) + unicode-types (1.9.0) unicode_utils (1.4.0) validatable (1.6.7) validate_email (0.1.6) @@ -1245,14 +1314,13 @@ GEM validate_url (1.0.15) activemodel (>= 3.0.0) public_suffix - valkyrie (2.2.0) + valkyrie (3.1.1) activemodel activesupport - disposable (~> 0.4.5) - draper dry-struct dry-types (~> 1.0) - faraday (< 1.0) + faraday (>= 0.9, < 3, != 2.0.0) + faraday-multipart json json-ld railties @@ -1260,49 +1328,65 @@ GEM rdf-vocab reform (~> 2.2) reform-rails - version_gem (1.1.2) + version_gem (1.1.3) + view_component (2.74.1) + activesupport (>= 5.0.0, < 8.0) + concurrent-ruby (~> 1.0) + method_source (~> 1.0) warden (1.2.9) rack (>= 2.0.9) - web-console (3.7.0) - actionview (>= 5.0) - activemodel (>= 5.0) + web-console (4.2.1) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) bindex (>= 0.4.0) - railties (>= 5.0) + railties (>= 6.0.0) webdrivers (4.7.0) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (> 3.141, < 5.0) - webfinger (1.2.0) + webfinger (2.1.2) activesupport - httpclient (>= 2.4) - webmock (3.18.1) + faraday (~> 2.0) + faraday-follow_redirects + webmock (3.19.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) - websocket (1.2.9) - websocket-driver (0.7.5) + websocket (1.2.10) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.8) + yaml-ld (0.0.2) + json-ld (~> 3.2, >= 3.2.3) + psych (>= 3.3) + rdf (~> 3.2, >= 3.2.9) + rdf-xsd (~> 3.2) + zeitwerk (2.6.12) + zlib (2.1.1) PLATFORMS - ruby + aarch64-linux-musl + x86_64-linux-musl DEPENDENCIES - active-fedora (>= 11.1.4) + active-fedora (~> 14.0) active_elastic_job! activerecord-nulldb-adapter addressable (= 2.8.1) - apartment + apartment! aws-sdk-sqs - blacklight (~> 6.7) - blacklight_oai_provider (~> 6.1, >= 6.1.1) + bixby (~> 5.0, >= 5.0.2) + blacklight (~> 7.29) + blacklight_advanced_search + blacklight_oai_provider (~> 7.0) + blacklight_range_limit bolognese (>= 1.9.10) + bootstrap (~> 4.6) bootstrap-datepicker-rails - bulkrax (~> 5.3) + bulkrax (~> 5.4) byebug capybara capybara-screenshot (~> 1.0) @@ -1314,15 +1398,16 @@ DEPENDENCIES devise devise-guests (~> 0.3) devise-i18n - devise_invitable (~> 1.6) - dry-monads (~> 1.4.0) + devise_invitable (~> 2.0) + dry-monads (~> 1.5) easy_translate factory_bot_rails fcrepo_wrapper (~> 0.4) - flipflop (~> 2.6.0) flutie + good_job (~> 2.99) + googleauth (= 1.8.1) hyku_knapsack! - hyrax (~> 3.5.0) + hyrax! hyrax-doi! hyrax-iiif_av! i18n-debug @@ -1342,17 +1427,19 @@ DEPENDENCIES omniauth-rails_csrf_protection (~> 1.0) omniauth-saml (~> 2.1) omniauth_openid_connect - parser (~> 2.5.3) + order_already + parser (>= 3.1.0.0) pg postrank-uri (>= 1.0.24) pry-byebug puma (~> 5.6) rack-test (= 0.7.0) - rails (~> 5.2.5) + rails (~> 6.0) rails-controller-testing - rdf (~> 3.1.15) + rdf (~> 3.2) + redis-namespace (~> 1.10) redlock (>= 0.1.2, < 2.0) - riiif (~> 1.1) + riiif (~> 2.0) rolify rsolr (~> 2.0) rspec @@ -1361,9 +1448,10 @@ DEPENDENCIES rspec-rails (>= 3.6.0) rspec-retry rspec_junit_formatter - rubocop (~> 0.50, <= 0.52.1) + rubocop (= 1.28.2) + rubocop-rails (~> 2.15) rubocop-rspec (~> 1.22, <= 1.22.2) - sass-rails (~> 5.0) + sass-rails (~> 6.0) scss_lint secure_headers selenium-webdriver (= 4.8.1) @@ -1376,9 +1464,10 @@ DEPENDENCIES terser tether-rails turbolinks (~> 5) + twitter-typeahead-rails (= 0.11.1.pre.corejavascript) web-console (>= 3.3.0) webdrivers (~> 4.7.0) webmock BUNDLED WITH - 2.4.14 + 2.4.21 diff --git a/README.md b/README.md index 1be23b504..d666a9f05 100644 --- a/README.md +++ b/README.md @@ -340,7 +340,7 @@ More info about configuring and using bulkrax can be found [here](https://github ### Commandline Importers -Importing from CSV and PURL directly can be done via Bulkrax and the built in code in Hyku is slated for deletion in the next release. +Importing from CSV and PURL directly can be done via Bulkrax. ## Compatibility diff --git a/Rakefile b/Rakefile index f55260d5d..ac6b3fbc9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. @@ -15,7 +17,9 @@ Rails.application.load_tasks begin require 'solr_wrapper/rake_task' +# rubocop:disable Lint/SuppressedException rescue LoadError + # rubocop:enable Lint/SuppressedException end task :ci do diff --git a/app/actors/hyrax/environment.rb b/app/actors/hyrax/environment_decorator.rb similarity index 51% rename from app/actors/hyrax/environment.rb rename to app/actors/hyrax/environment_decorator.rb index 814895f87..257f66b11 100644 --- a/app/actors/hyrax/environment.rb +++ b/app/actors/hyrax/environment_decorator.rb @@ -1,25 +1,21 @@ # frozen_string_literal: true -# OVERRIDE Hyrax 2.9 to add in import flag +# OVERRIDE Hyrax v5.0.0rc2 to add in import flag + module Hyrax module Actors - class Environment + module EnvironmentDecoractor # @param [ActiveFedora::Base] curation_concern work to operate on # @param [Ability] current_ability the authorizations of the acting user # @param [ActionController::Parameters] attributes user provided form attributes def initialize(curation_concern, current_ability, attributes, importing = false) - @curation_concern = curation_concern - @current_ability = current_ability - @attributes = attributes.to_h.with_indifferent_access @importing = importing + super(curation_concern, current_ability, attributes) end - attr_reader :curation_concern, :current_ability, :attributes, :importing - - # @return [User] the user from the current_ability - def user - current_ability.current_user - end + attr_reader :importing end end end + +Hyrax::Actors::Environment.prepend(Hyrax::Actors::EnvironmentDecoractor) diff --git a/app/assets/javascripts/admin_color_select.js b/app/assets/javascripts/admin_color_select.js new file mode 100644 index 000000000..371fc0b42 --- /dev/null +++ b/app/assets/javascripts/admin_color_select.js @@ -0,0 +1,20 @@ +$(document).on('turbolinks:load', function() { + $('div.defaultable-colors a.restore-default-color').click(function(e) { + e.preventDefault() + + var defaultTarget = $(e.target).data('default-target') + var input = $("input[name='admin_appearance["+ defaultTarget +"]']") + + input.val(input.data('default-value')) + }) + + $('.panel-footer a.restore-all-default-colors').click(function(e) { + e.preventDefault() + + var allColorInputs = $("input[name*='color']") + + allColorInputs.each(function() { + $(this).val($(this).data('default-value')) + }) + }) +}); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index df9e83c18..1f6185b0c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,14 +10,14 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // -//= require codemirror -//= require codemirror-autorefresh -//= require codemirror/modes/css //= require jquery3 -//= require jquery_ujs +//= require rails-ujs +//= require popper +//= require twitter/typeahead +//= require bootstrap //= require jquery.fontselect -//= require dataTables/jquery.dataTables -//= require dataTables/bootstrap/3/jquery.dataTables.bootstrap +//= require jquery.dataTables +//= require dataTables.bootstrap4 //= require stat_slider //= require turbolinks //= require cocoon @@ -25,6 +25,9 @@ //= require tether // Required by Blacklight //= require blacklight/blacklight +//= require blacklight_gallery +//= require admin_color_select +//= require blacklight_advanced_search // Moved the Hyku JS *above* the Hyrax JS to resolve #1187 (following // a pattern found in ScholarSphere) @@ -42,9 +45,23 @@ //= require bulkrax/application //= require hyrax + +//= require codemirror +//= require codemirror-autorefresh +//= require codemirror/modes/css + //= require iiif_print //= require jquery.flot.pie //= require flot_graph //= require statistics_tab_manager //= require blacklight_gallery/default + +// Required for blacklight range limit +//= require blacklight_range_limit/range_limit_distro_facets +//= require blacklight_range_limit/range_limit_shared +//= require blacklight_range_limit/range_limit_slider +//= require bootstrap-slider +//= require jquery.flot.js + +//= require tinymce diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js new file mode 100644 index 000000000..1133b8dec --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js @@ -0,0 +1,348 @@ +// for Blacklight.onLoad: + +/* A custom event "plotDrawn.blacklight.rangeLimit" will be sent when flot plot + is (re-)drawn on screen possibly with a new size. target of event will be the DOM element + containing the plot. Used to resize slider to match. */ + +Blacklight.onLoad(function () { + // ratio of width to height for desired display, multiply width by this ratio + // to get height. hard-coded in for now. + var display_ratio = 1 / (1.618 * 2); // half a golden rectangle, why not + var redrawnEvent = "plotDrawn.blacklight.rangeLimit"; + + // Facets already on the page? Turn em into a chart. + $(".range_limit .profile .distribution.chart_js ul").each(function () { + turnIntoPlot($(this).parent()); + }); + + // Add AJAX fetched range facets if needed, and add a chart to em + $(".range_limit .profile .distribution a.load_distribution").each( + function () { + var container = $(this).parent("div.distribution"); + + $(container).load($(this).attr("href"), function (response, status) { + if ($(container).hasClass("chart_js") && status == "success") { + turnIntoPlot(container); + } + }); + } + ); + + // Listen for twitter bootstrap collapsible open events, to render flot + // in previously hidden divs on open, if needed. + $("body").on("show.bs.collapse", function (event) { + // Was the target a .facet-content including a .chart-js? + var container = $(event.target).filter(".facet-content").find(".chart_js"); + + // only if it doesn't already have a canvas, it isn't already drawn + if (container && container.find("canvas").length == 0) { + // be willing to wait up to 1100ms for container to + // have width -- right away on show.bs is too soon, but + // shown.bs is later than we want, we want to start rendering + // while animation is still in progress. + turnIntoPlot(container, 1100); + } + }); + + // after a collapsible facet contents is fully shown, + // resize the flot chart to current conditions. This way, if you change + // browser window size, you can get chart resized to fit by closing and opening + // again, if needed. + + function redrawPlot(container) { + if (container && container.width() > 0) { + // resize the container's height, since width may have changed. + container.height(container.width() * display_ratio); + + // redraw the chart. + var plot = container.data("plot"); + if (plot) { + // how to redraw after possible resize? + // Cribbed from https://github.com/flot/flot/blob/master/jquery.flot.resize.js + plot.resize(); + plot.setupGrid(); + plot.draw(); + // plus trigger redraw of the selection, which otherwise ain't always right + // we'll trigger a fake event on one of the boxes + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin").trigger("change"); + + // send our custom event to trigger redraw of slider + $(container).trigger(redrawnEvent); + } + } + } + + $("body").on("shown.bs.collapse", function (event) { + var container = $(event.target).filter(".facet-content").find(".chart_js"); + redrawPlot(container); + }); + + // debouce borrowed from underscore + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + debounce = function (func, wait, immediate) { + var timeout; + return function () { + var context = this, + args = arguments; + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + }; + + $(window).on( + "resize", + debounce(function () { + $(".chart_js").each(function (i, container) { + redrawPlot($(container)); + }); + }, 350) + ); + + // second arg, if provided, is a number of ms we're willing to + // wait for the container to have width before giving up -- we'll + // set 50ms timers to check back until timeout is expired or the + // container is finally visible. The timeout is used when we catch + // bootstrap show event, but the animation hasn't barely begun yet -- but + // we don't want to wait until it's finished, we want to start rendering + // as soon as we can. + // + // We also will + function turnIntoPlot(container, wait_for_visible) { + // flot can only render in a a div with a defined width. + // for instance, a hidden div can't generally be rendered in (although if you set + // an explicit width on it, it might work) + // + // We'll count on later code that catch bootstrap collapse open to render + // on show, for currently hidden divs. + + // for some reason width sometimes return negative, not sure + // why but it's some kind of hidden. + if (container.width() > 0) { + var height = container.width() * display_ratio; + + // Need an explicit height to make flot happy. + container.height(height); + + areaChart($(container)); + + $(container).trigger(redrawnEvent); + } else if (wait_for_visible > 0) { + setTimeout(function () { + turnIntoPlot(container, wait_for_visible - 50); + }, 50); + } + } + + // Takes a div holding a ul of distribution segments produced by + // blacklight_range_limit/_range_facets and makes it into + // a flot area chart. + function areaChart(container) { + //flot loaded? And canvas element supported. + if (domDependenciesMet()) { + // Grab the data from the ul div + var series_data = new Array(); + var pointer_lookup = new Array(); + var x_ticks = new Array(); + var min = BlacklightRangeLimit.parseNum( + $(container).find("ul li:first-child span.from").text() + ); + var max = BlacklightRangeLimit.parseNum( + $(container).find("ul li:last-child span.to").text() + ); + + $(container) + .find("ul li") + .each(function () { + var from = BlacklightRangeLimit.parseNum( + $(this).find("span.from").text() + ); + var to = BlacklightRangeLimit.parseNum( + $(this).find("span.to").text() + ); + var count = BlacklightRangeLimit.parseNum( + $(this).find("span.count").text() + ); + var avg = count / (to - from + 1); + + //We use the avg as the y-coord, to make the area of each + //segment proportional to how many documents it holds. + series_data.push([from, avg]); + series_data.push([to + 1, avg]); + + x_ticks.push(from); + + pointer_lookup.push({ + from: from, + to: to, + count: count, + label: $(this).find(".facet_select").text(), + }); + }); + var max_plus_one = + BlacklightRangeLimit.parseNum( + $(container).find("ul li:last-child span.to").text() + ) + 1; + x_ticks.push(max_plus_one); + + var plot; + var config = + $(container).closest(".facet_limit").data("plot-config") || {}; + + try { + plot = $.plot( + $(container), + [series_data], + $.extend(true, config, { + yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 }, + //xaxis: { ticks: x_ticks }, + xaxis: { tickDecimals: 0 }, // force integer ticks + series: { lines: { fill: true, steps: true } }, + grid: { clickable: true, hoverable: true, autoHighlight: false }, + selection: { mode: "x" }, + }) + ); + } catch (err) { + alert(err); + } + + find_segment_for = function_for_find_segment(pointer_lookup); + var last_segment = null; + $(container).tooltip({ + placement: "bottom", + trigger: "manual", + delay: { show: 0, hide: 100 }, + }); + + $(container).bind("plothover", function (event, pos, item) { + segment = find_segment_for(pos.x); + + if (segment != last_segment) { + var title = + find_segment_for(pos.x).label + + " (" + + BlacklightRangeLimit.parseNum(segment.count) + + ")"; + $(container) + .attr("title", title) + .tooltip("_fixTitle") + .tooltip("show"); + + last_segment = segment; + } + }); + + $(container).bind("mouseout", function () { + last_segment = null; + $(container).tooltip("hide"); + }); + $(container).bind("plotclick", function (event, pos, item) { + if (plot.getSelection() == null) { + segment = find_segment_for(pos.x); + plot.setSelection(normalized_selection(segment.from, segment.to)); + } + }); + $(container).bind("plotselected plotselecting", function (event, ranges) { + if (ranges != null) { + var from = Math.floor(ranges.xaxis.from); + var to = Math.floor(ranges.xaxis.to); + + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin").val(from); + form.find("input.range_end").val(to); + + var slider_placeholder = $(container) + .closest(".limit_content") + .find("[data-slider-placeholder]"); + if (slider_placeholder) { + slider_placeholder.slider("setValue", [from, to + 1]); + } + } + }); + + var form = $(container) + .closest(".limit_content") + .find("form.range_limit"); + form.find("input.range_begin, input.range_end").change(function () { + plot.setSelection(form_selection(form, min, max), true); + }); + $(container) + .closest(".limit_content") + .find(".profile .range") + .on("slide", function (event, ui) { + var values = $(event.target).data("slider").getValue(); + form.find("input.range_begin").val(values[0]); + form.find("input.range_end").val(values[1]); + plot.setSelection( + normalized_selection(values[0], Math.max(values[0], values[1] - 1)), + true + ); + }); + + // initially entirely selected, to match slider + plot.setSelection({ xaxis: { from: min, to: max + 0.9999 } }); + } + } + + // Send endpoint to endpoint+0.99999 to have display + // more closely approximate limiting behavior esp + // at small resolutions. (Since we search on whole numbers, + // inclusive, but flot chart is decimal.) + function normalized_selection(min, max) { + max += 0.99999; + + return { xaxis: { from: min, to: max } }; + } + + function form_selection(form, min, max) { + var begin_val = BlacklightRangeLimit.parseNum( + $(form).find("input.range_begin").val() + ); + if (isNaN(begin_val) || begin_val < min) { + begin_val = min; + } + var end_val = BlacklightRangeLimit.parseNum( + $(form).find("input.range_end").val() + ); + if (isNaN(end_val) || end_val > max) { + end_val = max; + } + + return normalized_selection(begin_val, end_val); + } + + function function_for_find_segment(pointer_lookup_arr) { + return function (x_coord) { + for (var i = pointer_lookup_arr.length - 1; i >= 0; i--) { + var hash = pointer_lookup_arr[i]; + if (x_coord >= hash.from) return hash; + } + return pointer_lookup_arr[0]; + }; + } + + // Check if Flot is loaded, and if browser has support for + // canvas object, either natively or via IE excanvas. + function domDependenciesMet() { + var flotLoaded = typeof $.plot != "undefined"; + var canvasAvailable = + typeof document.createElement("canvas").getContext != "undefined" || + typeof window.CanvasRenderingContext2D != "undefined" || + typeof G_vmlCanvasManager != "undefined"; + + return flotLoaded && canvasAvailable; + } +}); diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js b/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js new file mode 100644 index 000000000..74aef9e9e --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_shared.js @@ -0,0 +1,24 @@ + +// takes a string and parses into an integer, but throws away commas first, to avoid truncation when there is a comma +// use in place of javascript's native parseInt +!function(global) { + 'use strict'; + + var previousBlacklightRangeLimit = global.BlacklightRangeLimit; + + function BlacklightRangeLimit(options) { + this.options = options || {}; + } + + BlacklightRangeLimit.parseNum = function parseNum(str) { + str = String(str).replace(/[^0-9]/g, ''); + return parseInt(str, 10); + }; + + BlacklightRangeLimit.noConflict = function noConflict() { + global.BlacklightRangeLimit = previousBlacklightRangeLimit; + return BlacklightRangeLimit; + }; + + global.BlacklightRangeLimit = BlacklightRangeLimit; +}(this); diff --git a/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js b/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js new file mode 100644 index 000000000..e29464229 --- /dev/null +++ b/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js @@ -0,0 +1,130 @@ +// for Blacklight.onLoad: + +Blacklight.onLoad(function() { + + $(".range_limit .profile .range.slider_js").each(function() { + var range_element = $(this); + + var boundaries = min_max(this); + var min = boundaries[0]; + var max = boundaries[1]; + + if (isInt(min) && isInt(max)) { + $(this).contents().wrapAll('
'); + + var range_element = $(this); + var form = $(range_element).closest(".range_limit").find("form.range_limit"); + var begin_el = form.find("input.range_begin"); + var end_el = form.find("input.range_end"); + + var placeholder_input = $('').appendTo(range_element); + + // make sure slider is loaded + if (placeholder_input.slider !== undefined) { + placeholder_input.slider({ + min: min, + max: max+1, + value: [min, max+1], + tooltip: "hide" + }); + + // try to make slider width/orientation match chart's + var container = range_element.closest(".range_limit"); + var plot = container.find(".chart_js").data("plot"); + var slider_el = container.find(".slider"); + + if (plot && slider_el) { + slider_el.width(plot.width()); + slider_el.css("display", "block") + slider_el.css('margin-right', 'auto'); + slider_el.css('margin-left', 'auto'); + } + else if (slider_el) { + slider_el.css("width", "100%"); + } + } + + // Slider change should update text input values. + var parent = $(this).parent(); + var form = $(parent).closest(".limit_content").find("form.range_limit"); + $(parent).closest(".limit_content").find(".profile .range").on("slide", function(event, ui) { + var values = $(event.target).data("slider").getValue(); + form.find("input.range_begin").val(values[0]); + form.find("input.range_end").val(values[1]); + }); + } + + begin_el.val(min); + end_el.val(max); + + begin_el.change( function() { + var val = BlacklightRangeLimit.parseNum($(this).val()); + if ( isNaN(val) || val < min) { + //for weird data, set slider at min + val = min; + } + var values = placeholder_input.data("slider").getValue(); + values[0] = val; + placeholder_input.slider("setValue", values); + }); + + end_el.change( function() { + var val = BlacklightRangeLimit.parseNum($(this).val()); + if ( isNaN(val) || val > max ) { + //weird entry, set slider to max + val = max; + } + var values = placeholder_input.data("slider").getValue(); + values[1] = val; + placeholder_input.slider("setValue", values); + }); + + }); + + // catch event for redrawing chart, to redraw slider to match width + $("body").on("plotDrawn.blacklight.rangeLimit", function(event) { + var area = $(event.target).closest(".limit_content.range_limit"); + var plot = area.find(".chart_js").data("plot"); + var slider_el = area.find(".slider"); + + if (plot && slider_el) { + slider_el.width(plot.width()); + slider_el.css("display", "block") + slider_el.css('margin-right', 'auto'); + slider_el.css('margin-left', 'auto'); + } + }); + + // returns two element array min/max as numbers. If there is a limit applied, + // it's boundaries are are limits. Otherwise, min/max in current result + // set as sniffed from HTML. Pass in a DOM element for a div.range + // Will return NaN as min or max in case of error or other weirdness. + function min_max(range_element) { + var current_limit = $(range_element).closest(".limit_content.range_limit").find(".current") + + + + var min = max = BlacklightRangeLimit.parseNum(current_limit.find(".single").text()) + if ( isNaN(min)) { + min = BlacklightRangeLimit.parseNum(current_limit.find(".from").first().text()); + max = BlacklightRangeLimit.parseNum(current_limit.find(".to").first().text()); + } + + if (isNaN(min) || isNaN(max)) { + //no current limit, take from results min max included in spans + min = BlacklightRangeLimit.parseNum($(range_element).find(".min").first().text()); + max = BlacklightRangeLimit.parseNum($(range_element).find(".max").first().text()); + } + + return [min, max] + } + + + // Check to see if a value is an Integer + // see: http://stackoverflow.com/questions/3885817/how-to-check-if-a-number-is-float-or-integer + function isInt(n) { + return n % 1 === 0; + } + + }); + \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 8b66c7d5d..280aa914c 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -15,8 +15,11 @@ *= require codemirror *= require codemirror-theme *= require hyrax - *= require dataTables/bootstrap/3/jquery.dataTables.bootstrap + *= require dataTables.bootstrap4 *= require bootstrap-datepicker *= require single_signon + *= require blacklight_advanced_search + *= require blacklight_range_limit *= require_self + *= require hyku_knapsack/application */ diff --git a/app/assets/stylesheets/hyku.scss b/app/assets/stylesheets/hyku.scss index 8979ddd16..3a2366f0d 100644 --- a/app/assets/stylesheets/hyku.scss +++ b/app/assets/stylesheets/hyku.scss @@ -16,7 +16,7 @@ } } -@media (min-width: $screen-sm-min) { +@media (min-width: 768px) { .logo-set { display: flex; flex-direction: column; @@ -61,6 +61,7 @@ margin-bottom: 20px; } + // TODO: Do we need this style or could we fallback on btn-primary .btn-sign-up { @include button-variant( $classic-white, @@ -131,7 +132,7 @@ footer.navbar { .sidebar { .h5 { - padding: $nav-link-padding; + padding: 10px 15px; } &.maximized { @@ -275,7 +276,7 @@ footer.navbar { } .callout-danger { - background-color: $well-bg; + background-color: #f5f5f5; border-color: $brand-danger; h1, @@ -374,7 +375,7 @@ a.btn.btn-default.restore-default-color.with-color-hint { height: auto; } -@media (min-width: $screen-lg-min) { +@media (min-width: 1200px) { a.restore-default-color { margin-top: 2em; } @@ -388,7 +389,7 @@ a.btn.btn-default.restore-default-color.with-color-hint { display: inline-block; } -@media (max-width: $screen-md-min) { +@media (max-width: 992px) { .product-features { .grid-item { width: 50%; @@ -396,7 +397,7 @@ a.btn.btn-default.restore-default-color.with-color-hint { } } -@media (max-width: $screen-sm-min) { +@media (max-width: 768px) { .product-features { .grid-item { width: 100%; @@ -433,7 +434,7 @@ body.public-facing { } // FEATURED COLLECTIONS -@media (max-width: $screen-sm-min) { +@media (max-width: 768px) { .admin-show-page .collection-title-row-wrapper .collection-title-row-content diff --git a/app/assets/stylesheets/hyrax.scss b/app/assets/stylesheets/hyrax.scss index 5efe46c15..411eca65f 100644 --- a/app/assets/stylesheets/hyrax.scss +++ b/app/assets/stylesheets/hyrax.scss @@ -5,18 +5,17 @@ */ @import "variables"; @import "bootstrap-default-overrides"; -@import "bootstrap-sprockets"; @import "bootstrap"; @import "blacklight/blacklight"; +@import "blacklight_gallery/gallery"; +@import "blacklight_gallery/masonry"; +@import "blacklight_gallery/slideshow"; +@import "blacklight_gallery/osd_viewer"; +@import "hyrax/blacklight_gallery"; @import "font-awesome"; @import "hyrax/hyrax"; @import "hyku"; @import "accounts"; @import "viewer"; -@import "blacklight_gallery/gallery"; -@import "blacklight_gallery/masonry"; -@import "blacklight_gallery/slideshow"; -@import "blacklight_gallery/osd_viewer"; - @import "themes/*"; diff --git a/app/assets/stylesheets/themes/cultural_repository.scss b/app/assets/stylesheets/themes/cultural_repository.scss index fc451c0c7..811e8e7dc 100644 --- a/app/assets/stylesheets/themes/cultural_repository.scss +++ b/app/assets/stylesheets/themes/cultural_repository.scss @@ -14,7 +14,7 @@ body.dashboard { padding-top: 100px !important; - @media (max-width: $screen-md-min) { + @media (max-width: 992px) { padding-top: 0 !important; } @@ -162,7 +162,7 @@ .facet-panel-background-color { background-color: #ffffff; - @media (max-width: $screen-md-min) { + @media (max-width: 992px) { background-color: transparent; } @@ -240,14 +240,14 @@ ////// Media Queries ////// - @media (min-width: $screen-xs-min) and (max-width: $screen-md-max) { + @media (min-width: 480px) and (max-width: 1199px) { .mt-reverse-mb { margin-bottom: 40px; margin-top: 0; } } - @media (max-width: $screen-sm-max) { + @media (max-width: 991px) { div.home_page_text.homepage-text-container { height: 0; margin-bottom: 30px; @@ -255,7 +255,7 @@ } } - @media screen and (max-width: $screen-md-min) { + @media screen and (max-width: 992px) { div.recently-uploaded:nth-of-type(2n+3), div.featured-works-6-column-layout:nth-of-type(2n+3), div.featured-works-4-column-layout:nth-of-type(2n+3) { diff --git a/app/assets/stylesheets/themes/neutral_repository.scss b/app/assets/stylesheets/themes/neutral_repository.scss index ec037fa89..26639ca41 100644 --- a/app/assets/stylesheets/themes/neutral_repository.scss +++ b/app/assets/stylesheets/themes/neutral_repository.scss @@ -152,13 +152,13 @@ ////// Media Queries ////// - @media (max-width: $screen-md-min) { + @media (max-width: 992px) { div.neutral-repository-collections:nth-of-type(2n+3) { clear: left; } } - @media (min-width: $screen-md-min) { + @media (min-width: 992px) { div.neutral-repository-collections:nth-of-type(3n+4) { clear: left; } diff --git a/app/controllers/account_sign_up_controller.rb b/app/controllers/account_sign_up_controller.rb index 89b06cb6e..c0fe62fae 100644 --- a/app/controllers/account_sign_up_controller.rb +++ b/app/controllers/account_sign_up_controller.rb @@ -27,24 +27,24 @@ def create private - def ensure_admin! - # Require Admin access to perform any actions - authorize! :read, :admin_dashboard - end + def ensure_admin! + # Require Admin access to perform any actions + authorize! :read, :admin_dashboard + end - def admin_only_tenant_creation? - ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYKU_ADMIN_ONLY_TENANT_CREATION', false)) - end + def admin_only_tenant_creation? + ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYKU_ADMIN_ONLY_TENANT_CREATION', false)) + end - def first_user_registration_url - if current_user - new_user_session_url(host: @account.cname) - else - new_user_registration_url(host: @account.cname) - end + def first_user_registration_url + if current_user + new_user_session_url(host: @account.cname) + else + new_user_registration_url(host: @account.cname) end + end - def create_params - params.require(:account).permit(:name) - end + def create_params + params.require(:account).permit(:name) + end end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index f27c0e2a7..d5028b217 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -28,12 +28,12 @@ def update private - def account_params - params.require(:account).permit(:name, :cname, :title, *@account.public_settings.keys) - end + def account_params + params.require(:account).permit(:name, :cname, :title, *@account.public_settings.keys) + end - def set_current_account - @account = Site.account - end + def set_current_account + @account = Site.account + end end end diff --git a/app/controllers/admin/group_roles_controller.rb b/app/controllers/admin/group_roles_controller.rb index d1966f2dd..1818e85a6 100644 --- a/app/controllers/admin/group_roles_controller.rb +++ b/app/controllers/admin/group_roles_controller.rb @@ -44,23 +44,23 @@ def destroy private - def load_group - @group = Hyrax::Group.find_by(id: params[:group_id]) - end + def load_group + @group = Hyrax::Group.find_by(id: params[:group_id]) + end - def redirect_not_found - flash[:error] = 'Unable to find Group Role with that ID' - redirect_to admin_group_roles_path(@group) - end + def redirect_not_found + flash[:error] = 'Unable to find Group Role with that ID' + redirect_to admin_group_roles_path(@group) + end - def cannot_remove_admin_role_from_admin_group - role = Role.find_by(id: params[:role_id]) - return unless @group.name == ::Ability.admin_group_name && role.name == 'admin' + def cannot_remove_admin_role_from_admin_group + role = Role.find_by(id: params[:role_id]) + return unless @group.name == ::Ability.admin_group_name && role.name == 'admin' - redirect_back( - fallback_location: edit_admin_group_path(@group), - flash: { error: "Admin role cannot be removed from this group" } - ) - end + redirect_back( + fallback_location: edit_admin_group_path(@group), + flash: { error: "Admin role cannot be removed from this group" } + ) + end end end diff --git a/app/controllers/admin/group_users_controller.rb b/app/controllers/admin/group_users_controller.rb index 3488fda4c..c7544ead0 100644 --- a/app/controllers/admin/group_users_controller.rb +++ b/app/controllers/admin/group_users_controller.rb @@ -32,25 +32,25 @@ def destroy private - def load_group - @group = Hyrax::Group.find_by(id: params[:group_id]) - end + def load_group + @group = Hyrax::Group.find_by(id: params[:group_id]) + end - def page_number - params.fetch(:page, 1).to_i - end + def page_number + params.fetch(:page, 1).to_i + end - def page_size - params.fetch(:per, 10).to_i - end + def page_size + params.fetch(:per, 10).to_i + end - def cannot_remove_admin_users_from_admin_group - return unless @group.name == ::Ability.admin_group_name + def cannot_remove_admin_users_from_admin_group + return unless @group.name == ::Ability.admin_group_name - redirect_back( - fallback_location: edit_admin_group_path(@group), - flash: { error: "Admin users cannot be removed from this group" } - ) - end + redirect_back( + fallback_location: edit_admin_group_path(@group), + flash: { error: "Admin users cannot be removed from this group" } + ) + end end end diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index c939ff5de..513ef190e 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -83,16 +83,16 @@ def destroy private - def group_params - params.require(:group).permit(:name, :humanized_name, :description) - end + def group_params + params.require(:group).permit(:name, :humanized_name, :description) + end - def page_number - params.fetch(:page, 1).to_i - end + def page_number + params.fetch(:page, 1).to_i + end - def page_size - params.fetch(:per, 10).to_i - end + def page_size + params.fetch(:per, 10).to_i + end end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index fa6740127..66d17cc44 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -20,16 +20,16 @@ def activate user.password = ENV.fetch('HYKU_USER_DEFAULT_PASSWORD', 'password') if user.save && user.accept_invitation! - redirect_to hyrax.admin_users_path, notice: t('hyrax.admin.users.activate.success', user: user) + redirect_to hyrax.admin_users_path, notice: t('hyrax.admin.users.activate.success', user:) else - redirect_to hyrax.admin_users_path, flash: { error: t('hyrax.admin.users.activate.failure', user: user) } + redirect_to hyrax.admin_users_path, flash: { error: t('hyrax.admin.users.activate.failure', user:) } end end private - def load_user - @user = User.from_url_component(params[:id]) - end + def load_user + @user = User.from_url_component(params[:id]) + end end end diff --git a/app/controllers/admin/work_types_controller.rb b/app/controllers/admin/work_types_controller.rb index babaf515c..105745775 100644 --- a/app/controllers/admin/work_types_controller.rb +++ b/app/controllers/admin/work_types_controller.rb @@ -24,8 +24,8 @@ def update private - def site - @site ||= Site.first - end + def site + @site ||= Site.first + end end end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 2f8d6cb33..e9005f827 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -7,11 +7,11 @@ class AdminController < ApplicationController private - def ensure_admin! - authorize! :read, :admin_dashboard - end + def ensure_admin! + authorize! :read, :admin_dashboard + end - def deny_access(_exception) - redirect_to main_app.root_url, alert: t('hyku.admin.flash.access_denied') - end + def deny_access(_exception) + redirect_to main_app.root_url, alert: t('hyku.admin.flash.access_denied') + end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9449da3c0..77730d697 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -6,8 +6,6 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception, prepend: true - force_ssl if: :ssl_configured? - helper Openseadragon::OpenseadragonHelper # Adds a few additional behaviors into the application controller include Blacklight::Controller @@ -24,7 +22,6 @@ class ApplicationController < ActionController::Base before_action :require_active_account!, if: :multitenant? before_action :set_account_specific_connections! before_action :elevate_single_tenant!, if: :singletenant? - skip_after_action :discard_flash_if_xhr rescue_from Apartment::TenantNotFound do raise ActionController::RoutingError, 'Not Found' @@ -32,107 +29,110 @@ class ApplicationController < ActionController::Base protected - def is_hidden - current_account.persisted? && !current_account.is_public? - end + # rubocop:disable Naming/PredicateName + def is_hidden + # rubocop:enable Naming/PredicateName + current_account.persisted? && !current_account.is_public? + end - def is_api_or_pdf - request.format.to_s.match('json') || - params[:print] || - request.path.include?('api') || - request.path.include?('pdf') - end + # rubocop:disable Naming/PredicateName + def is_api_or_pdf + # rubocop:enable Naming/PredicateName + request.format.to_s.match('json') || + params[:print] || + request.path.include?('api') || + request.path.include?('pdf') + end - def is_staging - ['staging'].include?(Rails.env) - end + # rubocop:disable Naming/PredicateName + def is_staging + # rubocop:enable Naming/PredicateName + ['staging'].include?(Rails.env) + end - ## - # Extra authentication for palni-palci during development phase - def authenticate_if_needed - # Disable this extra authentication in test mode - return true if Rails.env.test? - if (is_hidden || is_staging) && !is_api_or_pdf - authenticate_or_request_with_http_basic do |username, password| - username == "samvera" && password == "hyku" - end - end + ## + # Extra authentication for palni-palci during development phase + def authenticate_if_needed + # Disable this extra authentication in test mode + return true if Rails.env.test? + # rubocop:disable Naming/PredicateName + return unless (is_hidden || is_staging) && !is_api_or_pdf + # rubocop:enable Naming/PredicateName + authenticate_or_request_with_http_basic do |username, password| + username == "samvera" && password == "hyku" end + end - def super_and_current_users - users = Role.find_by(name: 'superadmin')&.users.to_a - users << current_user if current_user && !users.include?(current_user) - users - end + def super_and_current_users + users = Role.find_by(name: 'superadmin')&.users.to_a + users << current_user if current_user && !users.include?(current_user) + users + end private - def require_active_account! - return if singletenant? - return if devise_controller? - raise Apartment::TenantNotFound, "No tenant for #{request.host}" unless current_account.persisted? - end + def require_active_account! + return if singletenant? + return if devise_controller? + raise Apartment::TenantNotFound, "No tenant for #{request.host}" unless current_account.persisted? + end - def set_account_specific_connections! - current_account&.switch! - end + def set_account_specific_connections! + current_account&.switch! + end - def multitenant? - @multitenant ||= ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYKU_MULTITENANT', false)) - end + def multitenant? + @multitenant ||= ActiveModel::Type::Boolean.new.cast(ENV.fetch('HYKU_MULTITENANT', false)) + end - def singletenant? - !multitenant? - end + def singletenant? + !multitenant? + end - def elevate_single_tenant! - AccountElevator.switch!(current_account.cname) if current_account && root_host? - end + def elevate_single_tenant! + AccountElevator.switch!(current_account.cname) if current_account && root_host? + end - def root_host? - Account.canonical_cname(request.host) == Account.root_host - end + def root_host? + Account.canonical_cname(request.host) == Account.root_host + end - def admin_host? - return false if singletenant? - Account.canonical_cname(request.host) == Account.admin_host - end + def admin_host? + return false if singletenant? + Account.canonical_cname(request.host) == Account.admin_host + end - def current_account - @current_account ||= Account.from_request(request) - @current_account ||= if multitenant? - Account.new do |a| - a.build_solr_endpoint - a.build_fcrepo_endpoint - a.build_redis_endpoint - end - else - Account.single_tenant_default + def current_account + @current_account ||= Account.from_request(request) + @current_account ||= if multitenant? + Account.new do |a| + a.build_solr_endpoint + a.build_fcrepo_endpoint + a.build_redis_endpoint end - end - - # Find themes set on Site model, or return default - def home_page_theme - current_account.sites&.first&.home_theme || 'default_home' - end + else + Account.single_tenant_default + end + end - def show_page_theme - current_account.sites&.first&.show_theme || 'default_show' - end + # Find themes set on Site model, or return default + def home_page_theme + current_account.sites&.first&.home_theme || 'default_home' + end - def search_results_theme - current_account.sites&.first&.search_theme || 'list_view' - end + def show_page_theme + current_account.sites&.first&.show_theme || 'default_show' + end - # Add context information to the lograge entries - def append_info_to_payload(payload) - super - payload[:request_id] = request.uuid - payload[:user_id] = current_user.id if current_user - payload[:account_id] = current_account.cname if current_account - end + def search_results_theme + current_account.sites&.first&.search_theme || 'list_view' + end - def ssl_configured? - ActiveRecord::Type::Boolean.new.cast(current_account.ssl_configured) - end + # Add context information to the lograge entries + def append_info_to_payload(payload) + super + payload[:request_id] = request.uuid + payload[:user_id] = current_user.id if current_user + payload[:account_id] = current_account.cname if current_account + end end diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 72265252c..93d0ddf91 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -1,6 +1,9 @@ # frozen_string_literal: true +# rubocop:disable Metrics/ClassLength, Metrics/BlockLength class CatalogController < ApplicationController + include BlacklightAdvancedSearch::Controller + include BlacklightRangeLimit::ControllerOverride include Hydra::Catalog include Hydra::Controller::ControllerBehavior include BlacklightOaiProvider::Controller @@ -8,20 +11,33 @@ class CatalogController < ApplicationController # These before_action filters apply the hydra access controls before_action :enforce_show_permissions, only: :show - def self.uploaded_field - 'system_create_dtsi' + def self.created_field + 'date_created_ssim' + end + + def self.creator_field + 'creator_ssim' end def self.modified_field 'system_modified_dtsi' end + def self.title_field + 'title_ssim' + end + + def self.uploaded_field + 'system_create_dtsi' + end + # CatalogController-scope behavior and configuration for BlacklightIiifSearch include BlacklightIiifSearch::Controller configure_blacklight do |config| # IiifPrint index fields - config.add_index_field 'all_text_tsimv', highlight: true, helper_method: :render_ocr_snippets + config.add_index_field 'all_text_timv' + config.add_index_field 'file_set_text_tsimv', label: "Item contents", highlight: true, helper_method: :render_ocr_snippets # configuration for Blacklight IIIF Content Search config.iiif_search = { @@ -32,30 +48,42 @@ def self.modified_field suggester_name: 'iiifSuggester' } - config.view.gallery.partials = %i[index_header index] - config.view.masonry.partials = [:index] - config.view.slideshow.partials = [:index] - config.show.tile_source_field = :content_metadata_image_iiif_info_ssm config.show.partials.insert(1, :openseadragon) + # default advanced config values config.advanced_search ||= Blacklight::OpenStructWithHashAccess.new # config.advanced_search[:qt] ||= 'advanced' config.advanced_search[:url_key] ||= 'advanced' config.advanced_search[:query_parser] ||= 'dismax' config.advanced_search[:form_solr_parameters] ||= {} + config.advanced_search[:form_facet_partial] ||= "advanced_search_facets_as_select" config.search_builder_class = IiifPrint::CatalogSearchBuilder + # Use locally customized AdvSearchBuilder so we can enable blacklight_advanced_search + # TODO ROB config.search_builder_class = AdvSearchBuilder + # Show gallery view config.view.gallery.partials = %i[index_header index] + config.view.masonry.partials = [:index] config.view.slideshow.partials = [:index] + # Because too many times on Samvera tech people raise a problem regarding a failed query to SOLR. + # Often, it's because they inadvertently exceeded the character limit of a GET request. + config.http_method = :post + ## Default parameters to send to solr for all search-like requests. See also SolrHelper#solr_search_params config.default_solr_params = { qt: "search", rows: 10, - qf: "title_tesim description_tesim creator_tesim keyword_tesim all_text_timv" + qf: IiifPrint.config.metadata_fields.keys.map { |attribute| "#{attribute}_tesim" } + .join(' ') << " title_tesim description_tesim all_text_timv file_set_text_tsimv", # the first space character is necessary! + "hl": true, + "hl.simple.pre": "", + "hl.simple.post": "", + "hl.snippets": 30, + "hl.fragsize": 100 } # Specify which field to use in the tag cloud on the homepage. @@ -67,6 +95,18 @@ def self.modified_field config.index.display_type_field = 'has_model_ssim' config.index.thumbnail_field = 'thumbnail_path_ss' + # Blacklight 7 additions + config.add_results_document_tool(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?) + config.add_results_collection_tool(:sort_widget) + config.add_results_collection_tool(:per_page_widget) + config.add_results_collection_tool(:view_type_group) + config.add_show_tools_partial(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?) + config.add_show_tools_partial(:email, callback: :email_action, validator: :validate_email_params) + config.add_show_tools_partial(:sms, if: :render_sms_action?, callback: :sms_action, validator: :validate_sms_params) + config.add_show_tools_partial(:citation) + config.add_nav_action(:bookmark, partial: 'blacklight/nav/bookmark', if: :render_bookmarks_control?) + config.add_nav_action(:search_history, partial: 'blacklight/nav/search_history') + # solr fields that will be treated as facets by the blacklight application # The ordering of the field names is the order of the display config.add_facet_field 'human_readable_type_sim', label: "Type", limit: 5 @@ -81,6 +121,10 @@ def self.modified_field config.add_facet_field 'file_format_sim', limit: 5 config.add_facet_field 'member_of_collections_ssim', limit: 5, label: 'Collections' + # TODO: deal with part of facet changes + # config.add_facet_field solr_name("part", :facetable), limit: 5, label: 'Part' + # config.add_facet_field solr_name("part_of", :facetable), limit: 5 + # Have BL send all facet field names to Solr, which has been the default # previously. Simply remove these lines if you'd rather use Solr request # handler defaults, or have no facets. @@ -150,6 +194,7 @@ def self.modified_field # since we aren't specifying it otherwise. config.add_search_field('all_fields', label: 'All Fields', include_in_advanced_search: false) do |field| all_names = config.show_fields.values.map(&:field).join(" ") + title_name = 'title_tesim' field.solr_parameters = { qf: "#{all_names} file_format_tesim all_text_timv", @@ -178,6 +223,7 @@ def self.modified_field end config.add_search_field('creator') do |field| + # TODO: ROB field.label = "Author" field.solr_parameters = { "spellcheck.dictionary": "creator" } solr_name = 'creator_tesim' field.solr_local_parameters = { @@ -220,14 +266,15 @@ def self.modified_field } end + date_fields = ['date_created_tesim', 'sorted_date_isi', 'sorted_month_isi'] + config.add_search_field('date_created') do |field| field.solr_parameters = { "spellcheck.dictionary": "date_created" } - solr_name = 'created_tesim' field.solr_local_parameters = { - qf: solr_name, - pf: solr_name + qf: date_fields.join(' '), + pf: date_fields.join(' ') } end @@ -343,16 +390,27 @@ def self.modified_field } end + config.add_search_field('source') do |field| + solr_name = solr_name("source", :stored_searchable) + field.solr_local_parameters = { + qf: solr_name, + pf: solr_name + } + end + # "sort results by" select (pulldown) # label in pulldown is followed by the name of the SOLR field to sort by and # whether the sort is ascending or descending (it must be asc or desc # except in the relevancy case). # label is key, solr field is value - config.add_sort_field "score desc, #{uploaded_field} desc", label: "relevance" - config.add_sort_field "#{uploaded_field} desc", label: "date uploaded \u25BC" - config.add_sort_field "#{uploaded_field} asc", label: "date uploaded \u25B2" - config.add_sort_field "#{modified_field} desc", label: "date modified \u25BC" - config.add_sort_field "#{modified_field} asc", label: "date modified \u25B2" + config.add_sort_field "score desc, #{uploaded_field} desc", label: "Relevance" + + config.add_sort_field "#{title_field} asc", label: "Title" + config.add_sort_field "#{creator_field} asc", label: "Author" + config.add_sort_field "#{created_field} asc", label: "Published Date (Ascending)" + config.add_sort_field "#{created_field} desc", label: "Published Date (Descending)" + config.add_sort_field "#{modified_field} asc", label: "Upload Date (Ascending)" + config.add_sort_field "#{modified_field} desc", label: "Upload Date (Descending)" # OAI Config fields config.oai = { @@ -360,8 +418,8 @@ def self.modified_field repository_name: ->(controller) { controller.send(:current_account)&.name.presence }, # repository_url: ->(controller) { controller.oai_catalog_url }, record_prefix: ->(controller) { controller.send(:current_account).oai_prefix }, - admin_email: ->(controller) { controller.send(:current_account).oai_admin_email }, - sample_id: ->(controller) { controller.send(:current_account).oai_sample_identifier } + admin_email: ->(controller) { controller.send(:current_account).oai_admin_email }, + sample_id: ->(controller) { controller.send(:current_account).oai_sample_identifier } }, document: { limit: 100, # number of records returned with each request, default: 15 @@ -378,7 +436,8 @@ def self.modified_field # This is overridden just to give us a JSON response for debugging. def show - _, @document = fetch params[:id] + _, @document = search_service.fetch(params[:id]) render json: @document.to_h end end +# rubocop:enable Metrics/ClassLength, Metrics/BlockLength diff --git a/app/controllers/concerns/hyku/works_controller_behavior.rb b/app/controllers/concerns/hyku/works_controller_behavior.rb new file mode 100644 index 000000000..96b6f4e53 --- /dev/null +++ b/app/controllers/concerns/hyku/works_controller_behavior.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +# OVERRIDE: Hyrax v5.0.0rc2 to add inject_show_theme_views - Hyku theming +# and correct hostname of manifests +# and to add Hyrax IIIF AV +module Hyku + # include this module after including Hyrax::WorksControllerBehavior to override + # Hyrax::WorksControllerBehavior methods with the ones defined here + module WorksControllerBehavior + extend ActiveSupport::Concern + + # Adds behaviors for hyrax-iiif_av plugin and provides #manifest and #iiif_manifest_builder + include Hyrax::IiifAv::ControllerBehavior + + included do + # add around action to load theme show page views + around_action :inject_show_theme_views, except: :delete + end + + def json_manifest + iiif_manifest_builder.manifest_for(presenter: iiif_manifest_presenter) + end + + private + + def iiif_manifest_presenter + Hyrax::IiifManifestPresenter.new(search_result_document(id: params[:id])).tap do |p| + p.hostname = request.hostname + p.ability = current_ability + end + end + + def format_error_messages(errors) + errors.messages.map do |field, messages| + field_name = field.to_s.humanize + messages.map { |message| "#{field_name} #{message.sub(/^./, &:downcase)}" } + end.flatten.join("\n") + end + + # Creating a form object that can re-render most of the submitted parameters. + # Required for ActiveFedora::Base objects only. + def rebuild_form(original_input_params_for_form) + build_form + @form = Hyrax::Forms::FailedSubmissionFormWrapper + .new(form: @form, + input_params: original_input_params_for_form) + end + + def after_update_error(errors) + respond_to do |wants| + wants.html do + flash[:error] = format_error_messages(errors) + build_form unless @form.is_a? Hyrax::ChangeSet + render 'edit', status: :unprocessable_entity + end + wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: }) } + end + end + + def available_admin_sets + # only returns admin sets in which the user can deposit + admin_set_results = Hyrax::AdminSetService.new(self).search_results(:deposit) + + # get all the templates at once, reducing query load + templates = Hyrax::PermissionTemplate.where(source_id: admin_set_results.map(&:id)).to_a + + admin_sets = admin_set_results.map do |admin_set_doc| + template = templates.find { |temp| temp.source_id == admin_set_doc.id.to_s } + + ## OVERRIDE Hyrax v5.0.0rc2 + # Removes a short-circuit that allowed users with manage access to + # the given permission_template to always be able to edit a record's sharing + # (i.e. the "Sharing" tab in forms). + # + # We remove this because there is currently a bug in Hyrax where, if the + # workflow does not allow access grants, changes to a record's sharing + # are not being persisted, leading to a confusing UX. + # @see https://github.com/samvera/hyrax/issues/5904 + # + # TEMPORARY: This override should be removed when the bug is resolved in + # upstream Hyrax and brought into this project. + # + # determine if sharing tab should be visible + sharing = !!template&.active_workflow&.allows_access_grant? + + Hyrax::AdminSetSelectionPresenter::OptionsEntry + .new(admin_set: admin_set_doc, permission_template: template, permit_sharing: sharing) + end + + Hyrax::AdminSetSelectionPresenter.new(admin_sets:) + end + + # added to prepend the show theme views into the view_paths + def inject_show_theme_views + if show_page_theme && show_page_theme != 'default_show' + original_paths = view_paths + Hyku::Application.theme_view_path_roots.each do |root| + show_theme_view_path = File.join(root, 'app', 'views', "themes", show_page_theme.to_s) + prepend_view_path(show_theme_view_path) + end + yield + # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. + view_paths=(original_paths) + # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + else + yield + end + end + end +end diff --git a/app/controllers/concerns/hyrax/admin/users_controller_behavior.rb b/app/controllers/concerns/hyrax/admin/users_controller_behavior.rb index cd4d075e9..d58ad7ce0 100644 --- a/app/controllers/concerns/hyrax/admin/users_controller_behavior.rb +++ b/app/controllers/concerns/hyrax/admin/users_controller_behavior.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 Authorize User access and set up roles dropdown +# OVERRIDE Hyrax v5.0.0rc2 Authorize User access and set up roles dropdown module Hyrax module Admin module UsersControllerBehavior extend ActiveSupport::Concern include Blacklight::SearchContext included do - # OVERRIDE Hyrax v3.4.2 Replace :ensure_admin! with :ensure_access! to leverage User abilities. + # OVERRIDE Hyrax v5.0.0rc2 Replace :ensure_admin! with :ensure_access! to leverage User abilities. # @see app/models/concerns/hyrax/ability/user_ability.rb before_action :ensure_access! with_themed_layout 'dashboard' @@ -19,7 +19,7 @@ def index add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path add_breadcrumb t(:'hyrax.admin.users.index.title'), hyrax.admin_users_path @presenter = Hyrax::Admin::UsersPresenter.new - # OVERRIDE Hyrax v3.4.2 Sets up a list of role names to be used by a dropdown input that + # OVERRIDE Hyrax v5.0.0rc2 Sets up a list of role names to be used by a dropdown input that # allows users to be invited with a specific role. @invite_roles_options = if current_ability.admin? ::RolesService::DEFAULT_ROLES @@ -30,11 +30,11 @@ def index private - # OVERRIDE Hyrax v3.4.2 Replace :ensure_admin! with :ensure_access! to leverage User abilities. - # @see app/models/concerns/hyrax/ability/user_ability.rb - def ensure_access! - authorize! :read, ::User - end + # OVERRIDE Hyrax v5.0.0rc2 Replace :ensure_admin! with :ensure_access! to leverage User abilities. + # @see app/models/concerns/hyrax/ability/user_ability.rb + def ensure_access! + authorize! :read, ::User + end end end end diff --git a/app/controllers/concerns/hyrax/users_controller_decorator.rb b/app/controllers/concerns/hyrax/users_controller_decorator.rb index 98f6ca53e..bdbc358bc 100644 --- a/app/controllers/concerns/hyrax/users_controller_decorator.rb +++ b/app/controllers/concerns/hyrax/users_controller_decorator.rb @@ -11,28 +11,28 @@ module UsersControllerDecorator private - def users_match! - # The #find_user method is a :before_action on the Hyrax::UsersController. It sets - # the @user variable, which we need in this method. - # - # However, because we are decorating Hyrax::UsersController with this module, - # this method's :before_action will fire before the one that calls #find_user. - # This means that #find_user will fire a second time after this method runs. - # - # This is not ideal, but after discussing with @jeremyf, we decided that this is - # the "lesser evil" compared to other override methods (i.e. using #class_eval, - # overriding the entire file, etc.); since User is an ActiveRecord object, the - # database query that sets @user in #find_user will be cached. - # - # Classes that inherit from Hyrax::UsersController do not have this problem - # (e.g. Hyrax::Dashboard::ProfilesController), which is why we check for presence. - find_user if @user.blank? + def users_match! + # The #find_user method is a :before_action on the Hyrax::UsersController. It sets + # the @user variable, which we need in this method. + # + # However, because we are decorating Hyrax::UsersController with this module, + # this method's :before_action will fire before the one that calls #find_user. + # This means that #find_user will fire a second time after this method runs. + # + # This is not ideal, but after discussing with @jeremyf, we decided that this is + # the "lesser evil" compared to other override methods (i.e. using #class_eval, + # overriding the entire file, etc.); since User is an ActiveRecord object, the + # database query that sets @user in #find_user will be cached. + # + # Classes that inherit from Hyrax::UsersController do not have this problem + # (e.g. Hyrax::Dashboard::ProfilesController), which is why we check for presence. + find_user if @user.blank? - return if can?(:read, @user) - return if current_user == @user + return if can?(:read, @user) + return if current_user == @user - raise CanCan::AccessDenied - end + raise CanCan::AccessDenied + end end end diff --git a/app/controllers/concerns/hyrax/works_controller_behavior.rb b/app/controllers/concerns/hyrax/works_controller_behavior.rb deleted file mode 100644 index f5b51f64f..000000000 --- a/app/controllers/concerns/hyrax/works_controller_behavior.rb +++ /dev/null @@ -1,522 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE: Hyrax 3.4.0 to add inject_show_theme_views - Hyku theming and correct hostname of manifests -# OVERRIDE: Hyrax 3.4.0 to add Hyrax IIIF AV -require 'iiif_manifest' - -# rubocop:disable Metrics/ModuleLength -# rubocop:disable Metrics/LineLength -module Hyrax - module WorksControllerBehavior - extend ActiveSupport::Concern - include Blacklight::Base - include Blacklight::AccessControls::Catalog - - # Adds behaviors for hyrax-iiif_av plugin and provides #manifest and #iiif_manifest_builder - include Hyrax::IiifAv::ControllerBehavior - - included do - with_themed_layout :decide_layout - copy_blacklight_config_from(::CatalogController) - - class_attribute :_curation_concern_type, :show_presenter, :work_form_service, :search_builder_class - class_attribute :iiif_manifest_builder, instance_accessor: false - self.show_presenter = Hyku::WorkShowPresenter - self.work_form_service = Hyrax::WorkFormService - self.search_builder_class = WorkSearchBuilder - # Set to nil for the #iiif_manifest_builder (provided by Hyrax::IiifAv) to work - self.iiif_manifest_builder = nil - - attr_accessor :curation_concern - helper_method :curation_concern, :contextual_path - - rescue_from WorkflowAuthorizationException, with: :render_unavailable - # add around action to load theme show page views - around_action :inject_show_theme_views, except: :delete # rubocop:disable Rails/LexicallyScopedActionFilter - end - - class_methods do - def curation_concern_type=(curation_concern_type) - load_and_authorize_resource class: curation_concern_type, - instance_name: :curation_concern, - except: %i[show file_manager inspect_work manifest] - - # Load the fedora resource to get the etag. - # No need to authorize for the file manager, because it does authorization via the presenter. - load_resource class: curation_concern_type, instance_name: :curation_concern, only: :file_manager - - self._curation_concern_type = curation_concern_type - # We don't want the breadcrumb action to occur until after the concern has - # been loaded and authorized - before_action :save_permissions, only: :update # rubocop:disable Rails/LexicallyScopedActionFilter - end - - def curation_concern_type - _curation_concern_type - end - - def cancan_resource_class - Hyrax::ControllerResource - end - end - - def new - @admin_set_options = available_admin_sets - # TODO: move these lines to the work form builder in Hyrax - curation_concern.depositor = current_user.user_key - curation_concern.admin_set_id = admin_set_id_for_new - build_form - end - - def create - case curation_concern - when ActiveFedora::Base - original_input_params_for_form = params[hash_key_for_curation_concern].deep_dup - actor.create(actor_environment) ? after_create_response : after_create_error(curation_concern.errors, original_input_params_for_form) - else - create_valkyrie_work - end - end - - # Finds a solr document matching the id and sets @presenter - # @raise CanCan::AccessDenied if the document is not found or the user doesn't have access to it. - def show - @user_collections = user_collections - - respond_to do |wants| - wants.html { presenter && parent_presenter } - wants.json do - # load @curation_concern manually because it's skipped for html - @curation_concern = Hyrax.query_service.find_by(alternate_identifier: params[:id]) - curation_concern # This is here for authorization checks (we could add authorize! but let's use the same method for CanCanCan) - render :show, status: :ok - end - additional_response_formats(wants) - wants.ttl { render body: presenter.export_as_ttl, mime_type: Mime[:ttl] } - wants.jsonld { render body: presenter.export_as_jsonld, mime_type: Mime[:jsonld] } - wants.nt { render body: presenter.export_as_nt, mime_type: Mime[:nt] } - end - end - # rubocop:enable Metrics/AbcSize - - def edit - @admin_set_options = available_admin_sets - build_form - end - - def update - case curation_concern - when ActiveFedora::Base - actor.update(actor_environment) ? after_update_response : after_update_error(curation_concern.errors) - else - update_valkyrie_work - end - end - - def destroy - case curation_concern - when ActiveFedora::Base - title = curation_concern.to_s - env = Actors::Environment.new(curation_concern, current_ability, {}) - return unless actor.destroy(env) - Hyrax.config.callback.run(:after_destroy, curation_concern.id, current_user, warn: false) - else - transactions['work_resource.destroy'] - .with_step_args('work_resource.delete' => { user: current_user }) - .call(curation_concern) - .value! - - title = Array(curation_concern.title).first - end - - after_destroy_response(title) - end - - def file_manager - @form = Forms::FileManagerForm.new(curation_concern, current_ability) - end - - def inspect_work - raise Hydra::AccessDenied unless current_ability.admin? - presenter - end - - def json_manifest - iiif_manifest_builder.manifest_for(presenter: iiif_manifest_presenter) - end - - private - - def iiif_manifest_presenter - IiifManifestPresenter.new(search_result_document(id: params[:id])).tap do |p| - p.hostname = request.hostname - p.ability = current_ability - end - end - - def user_collections - collections_service.search_results(:deposit) - end - - def collections_service - Hyrax::CollectionsService.new(self) - end - - def admin_set_id_for_new - Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id.to_s - end - - def build_form - @form = work_form_service.build(curation_concern, current_ability, self) - end - - def actor - @actor ||= Hyrax::CurationConcern.actor - end - - ## - # @return [#errors] - def create_valkyrie_work - form = build_form - return after_create_error(form_err_msg(form)) unless form.validate(params[hash_key_for_curation_concern]) - - result = - transactions['change_set.create_work'] - .with_step_args( - 'work_resource.add_to_parent' => { parent_id: params[:parent_id], user: current_user }, - 'work_resource.add_file_sets' => { uploaded_files: uploaded_files, file_set_params: params[hash_key_for_curation_concern][:file_set] }, - 'change_set.set_user_as_depositor' => { user: current_user }, - 'work_resource.change_depositor' => { user: ::User.find_by_user_key(form.on_behalf_of) } - ) - .call(form) - @curation_concern = result.value_or { return after_create_error(transaction_err_msg(result)) } - after_create_response - end - - def update_valkyrie_work - form = build_form - return after_update_error(form_err_msg(form)) unless form.validate(params[hash_key_for_curation_concern]) - result = - transactions['change_set.update_work'] - .with_step_args('work_resource.add_file_sets' => { uploaded_files: uploaded_files, file_set_params: params[hash_key_for_curation_concern][:file_set] }, - 'work_resource.update_work_members' => { work_members_attributes: work_members_attributes }) - .call(form) - @curation_concern = result.value_or { return after_update_error(transaction_err_msg(result)) } - after_update_response - end - - def work_members_attributes - params[hash_key_for_curation_concern][:work_members_attributes]&.permit!&.to_h - end - - def form_err_msg(form) - form.errors.messages.values.flatten.to_sentence - end - - def transaction_err_msg(result) - result.failure.first - end - - def presenter - @presenter ||= show_presenter.new(search_result_document(id: params[:id]), current_ability, request) - end - - def parent_presenter - return @parent_presenter unless params[:parent_id] - - @parent_presenter ||= - show_presenter.new(search_result_document(id: params[:parent_id]), current_ability, request) - end - - # Include 'hyrax/base' in the search path for views, while prefering - # our local paths. Thus we are unable to just override `self.local_prefixes` - def _prefixes - @_prefixes ||= super + ['hyrax/base'] - end - - def actor_environment - Actors::Environment.new(curation_concern, current_ability, attributes_for_actor) - end - - def hash_key_for_curation_concern - _curation_concern_type.model_name.param_key - end - - def contextual_path(presenter, parent_presenter) - ::Hyrax::ContextualPath.new(presenter, parent_presenter).show - end - - # @deprecated - def curation_concern_from_search_results - Deprecation.warn("'##{__method__}' will be removed in Hyrax 4.0. " \ - "Instead, use '#search_result_document'.") - search_params = params.deep_dup - search_params.delete :page - search_result_document(search_params) - end - - ## - # Only returns unsuppressed documents the user has read access to - # - # @api public - # - # @param search_params [ActionController::Parameters] this should - # include an :id key, but based on implementation and use of the - # WorkSearchBuilder, it need not. - # - # @return [SolrDocument] - # - # @raise [WorkflowAuthorizationException] when the object is not - # found via the search builder's search logic BUT the object is - # suppressed AND the user can read it (Yeah, it's confusing but - # after a lot of debugging that's the logic) - # - # @raise [CanCan::AccessDenied] when the object is not found via - # the search builder's search logic BUT the object is not - # supressed OR not readable by the user (Yeah.) - # - # @note This is Jeremy, I have suspicions about the first line of - # this comment (eg, "Only return unsuppressed..."). The - # reason is that I've encounter situations in the specs - # where the document_list is empty but if I then query Solr - # for the object by ID, I get a document that is NOT - # suppressed AND can be read. In other words, I believe - # there is more going on in the search_results method - # (e.g. a filter is being applied that is beyond what the - # comment indicates) - # - # @see #document_not_found! - def search_result_document(search_params) - _, document_list = search_results(search_params) - return document_list.first unless document_list.empty? - document_not_found! - end - - def document_not_found! - doc = ::SolrDocument.find(params[:id]) - raise WorkflowAuthorizationException if doc.suppressed? && current_ability.can?(:read, doc) - raise CanCan::AccessDenied.new(nil, :show) - end - - def render_unavailable - message = I18n.t("hyrax.workflow.unauthorized") - respond_to do |wants| - wants.html do - unavailable_presenter - flash[:notice] = message - render 'unavailable', status: :unauthorized - end - wants.json { render plain: message, status: :unauthorized } - additional_response_formats(wants) - wants.ttl { render plain: message, status: :unauthorized } - wants.jsonld { render plain: message, status: :unauthorized } - wants.nt { render plain: message, status: :unauthorized } - end - end - - def unavailable_presenter - @presenter ||= show_presenter.new(::SolrDocument.find(params[:id]), current_ability, request) - end - - def decide_layout - layout = case action_name - when 'show' - '1_column' - else - 'dashboard' - end - File.join(theme, layout) - end - - ## - # @todo should the controller know so much about browse_everything? - # hopefully this can be refactored to be more reusable. - # - # Add uploaded_files to the parameters received by the actor. - def attributes_for_actor - raw_params = params[hash_key_for_curation_concern] - attributes = if raw_params - work_form_service.form_class(curation_concern).model_attributes(raw_params) - else - {} - end - - # If they selected a BrowseEverything file, but then clicked the - # remove button, it will still show up in `selected_files`, but - # it will no longer be in uploaded_files. By checking the - # intersection, we get the files they added via BrowseEverything - # that they have not removed from the upload widget. - uploaded_files = params.fetch(:uploaded_files, []) - selected_files = params.fetch(:selected_files, {}).values - browse_everything_urls = uploaded_files & - selected_files.map { |f| f[:url] } - - # we need the hash of files with url and file_name - browse_everything_files = selected_files - .select { |v| uploaded_files.include?(v[:url]) } - attributes[:remote_files] = browse_everything_files - # Strip out any BrowseEverthing files from the regular uploads. - attributes[:uploaded_files] = uploaded_files - - browse_everything_urls - attributes - end - - def after_create_response - respond_to do |wants| - wants.html do - # Calling `#t` in a controller context does not mark _html keys as html_safe - flash[:notice] = view_context.t('hyrax.works.create.after_create_html', application_name: view_context.application_name) - - redirect_to [main_app, curation_concern] - end - wants.json { render :show, status: :created, location: polymorphic_path([main_app, curation_concern]) } - end - end - - def format_error_messages(errors) - errors.messages.map do |field, messages| - field_name = field.to_s.humanize - messages.map { |message| "#{field_name} #{message.sub(/^./, &:downcase)}" } - end.flatten.join("\n") - end - - def after_create_error(errors, original_input_params_for_form = nil) - respond_to do |wants| - wants.html do - flash[:error] = format_error_messages(errors) - rebuild_form(original_input_params_for_form) if original_input_params_for_form.present? - render 'new', status: :unprocessable_entity - end - wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: errors }) } - end - end - - # Creating a form object that can re-render most of the submitted parameters. - # Required for ActiveFedora::Base objects only. - def rebuild_form(original_input_params_for_form) - build_form - @form = Hyrax::Forms::FailedSubmissionFormWrapper - .new(form: @form, - input_params: original_input_params_for_form) - end - - def after_update_response - return redirect_to hyrax.confirm_access_permission_path(curation_concern) if permissions_changed? && concern_has_file_sets? - - respond_to do |wants| - wants.html { redirect_to [main_app, curation_concern], notice: "Work \"#{curation_concern}\" successfully updated." } - wants.json { render :show, status: :ok, location: polymorphic_path([main_app, curation_concern]) } - end - end - - def after_update_error(errors) - respond_to do |wants| - wants.html do - flash[:error] = format_error_messages(errors) - build_form unless @form.is_a? Hyrax::ChangeSet - render 'edit', status: :unprocessable_entity - end - wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: errors }) } - end - end - - def after_destroy_response(title) - respond_to do |wants| - wants.html { redirect_to hyrax.my_works_path, notice: "Deleted #{title}" } - wants.json { render_json_response(response_type: :deleted, message: "Deleted #{curation_concern.id}") } - end - end - - def additional_response_formats(format) - format.endnote do - send_data(presenter.solr_document.export_as_endnote, - type: "application/x-endnote-refer", - filename: presenter.solr_document.endnote_filename) - end - end - - def save_permissions - @saved_permissions = - case curation_concern - when ActiveFedora::Base - curation_concern.permissions.map(&:to_hash) - else - Hyrax::AccessControl.for(resource: curation_concern).permissions - end - end - - def permissions_changed? - @saved_permissions != - case curation_concern - when ActiveFedora::Base - curation_concern.permissions.map(&:to_hash) - else - Hyrax::AccessControl.for(resource: curation_concern).permissions - end - end - - def concern_has_file_sets? - case curation_concern - when ActiveFedora::Common - curation_concern.file_sets.present? - else - Hyrax.custom_queries.find_child_file_set_ids(resource: curation_concern).any? - end - end - - def uploaded_files - UploadedFile.find(params.fetch(:uploaded_files, [])) - end - - def available_admin_sets - # only returns admin sets in which the user can deposit - admin_set_results = Hyrax::AdminSetService.new(self).search_results(:deposit) - - # get all the templates at once, reducing query load - templates = PermissionTemplate.where(source_id: admin_set_results.map(&:id)).to_a - - admin_sets = admin_set_results.map do |admin_set_doc| - template = templates.find { |temp| temp.source_id == admin_set_doc.id.to_s } - - ## OVERRIDE Hyrax v3.4.2 - # Removes a short-circuit that allowed users with manage access to - # the given permission_template to always be able to edit a record's sharing - # (i.e. the "Sharing" tab in forms). - # - # We remove this because there is currently a bug in Hyrax where, if the - # workflow does not allow access grants, changes to a record's sharing - # are not being persisted, leading to a confusing UX. - # @see https://github.com/samvera/hyrax/issues/5904 - # - # TEMPORARY: This override should be removed when the bug is resolved in - # upstream Hyrax and brought into this project. - # - # determine if sharing tab should be visible - sharing = !!template&.active_workflow&.allows_access_grant? # rubocop:disable Style/DoubleNegation - - AdminSetSelectionPresenter::OptionsEntry - .new(admin_set: admin_set_doc, permission_template: template, permit_sharing: sharing) - end - - AdminSetSelectionPresenter.new(admin_sets: admin_sets) - end - - # added to prepend the show theme views into the view_paths - def inject_show_theme_views - if show_page_theme && show_page_theme != 'default_show' - original_paths = view_paths - show_theme_view_path = Rails.root.join('app', 'views', "themes", show_page_theme.to_s) - prepend_view_path(show_theme_view_path) - yield - # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. - view_paths=(original_paths) - # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - else - yield - end - end - end -end -# rubocop:enable Metrics/ModuleLength -# rubocop:enable Metrics/LineLength diff --git a/app/controllers/hyku/invitations_controller.rb b/app/controllers/hyku/invitations_controller.rb index 2aa11fcac..68fe8d21e 100644 --- a/app/controllers/hyku/invitations_controller.rb +++ b/app/controllers/hyku/invitations_controller.rb @@ -10,6 +10,7 @@ def after_invite_path_for(_resource) # override the standard invite so that accounts are added properly # if they already exist on another tenant and invited if they do not + # rubocop:disable Metrics/AbcSize def create authorize! :grant_admin_role, User if params[:user][:role] == ::RolesService::ADMIN_ROLE self.resource = User.find_by(email: params[:user][:email]) || invite_resource @@ -20,20 +21,19 @@ def create yield resource if block_given? # Override destination as this was a success either way - if is_flashing_format? && resource.invitation_sent_at - set_flash_message :notice, :send_instructions, email: resource.email - end + set_flash_message :notice, :send_instructions, email: resource.email if is_flashing_format? && resource.invitation_sent_at if method(:after_invite_path_for).arity == 1 respond_with resource, location: after_invite_path_for(current_inviter) else respond_with resource, location: after_invite_path_for(current_inviter, resource) end end + # rubocop:enable Metrics/AbcSize protected - def user_params - params.require(:user).permit(:email, :role) - end + def user_params + params.require(:user).permit(:email, :role) + end end end diff --git a/app/controllers/hyku/registrations_controller.rb b/app/controllers/hyku/registrations_controller.rb index fe9a9422a..758cf0afb 100644 --- a/app/controllers/hyku/registrations_controller.rb +++ b/app/controllers/hyku/registrations_controller.rb @@ -15,8 +15,8 @@ def create private - def configure_permitted_parameters - devise_parameter_sanitizer.permit(:sign_up, keys: [:display_name]) - end + def configure_permitted_parameters + devise_parameter_sanitizer.permit(:sign_up, keys: [:display_name]) + end end end diff --git a/app/controllers/hyrax/admin/appearances_controller.rb b/app/controllers/hyrax/admin/appearances_controller.rb deleted file mode 100644 index b37308ebc..000000000 --- a/app/controllers/hyrax/admin/appearances_controller.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax 3.4 to add selectable themes - -module Hyrax - module Admin - class AppearancesController < ApplicationController - before_action :require_permissions - with_themed_layout 'dashboard' - class_attribute :form_class - self.form_class = Hyrax::Forms::Admin::Appearance - - def show - # TODO: make selected font the font that show in select box - # TODO add body and headline font to the import url - add_breadcrumbs - @form = form_class.new - @fonts = [@form.headline_font, @form.body_font] - @home_theme_information = YAML.load_file('config/home_themes.yml') - @show_theme_information = YAML.load_file('config/show_themes.yml') - @home_theme_names = load_home_theme_names - @show_theme_names = load_show_theme_names - @search_themes = load_search_themes - - flash[:alert] = t('hyrax.admin.appearances.show.forms.custom_css.warning') - end - - def update - form_class.new(update_params).update! - - if update_params['default_collection_image'] - # Reindex all Collections and AdminSets to apply new default collection image - ReindexCollectionsJob.perform_later - ReindexAdminSetsJob.perform_later - end - - if update_params['default_work_image'] - # Reindex all Works to apply new default work image - ReindexWorksJob.perform_later - end - - redirect_to({ action: :show }, notice: t('.flash.success')) - end - - private - - def update_params - params.require(:admin_appearance).permit(form_class.permitted_params) - end - - def require_permissions - authorize! :update, :appearance - end - - def add_breadcrumbs - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t(:'hyrax.admin.sidebar.configuration'), '#' - add_breadcrumb t(:'hyrax.admin.sidebar.appearance'), request.path - end - - def load_home_theme_names - home_theme_names = [] - @home_theme_information.each do |theme, value_hash| - value_hash.each do |key, value| - home_theme_names << [value, theme] if key == 'name' - end - end - home_theme_names - end - - def load_show_theme_names - show_theme_names = [] - @show_theme_information.each do |theme, value_hash| - value_hash.each do |key, value| - show_theme_names << [value, theme] if key == 'name' - end - end - show_theme_names - end - - def load_search_themes - { - 'List view' => 'list_view', - 'Gallery view' => 'gallery_view' - } - end - end - end -end diff --git a/app/controllers/hyrax/admin/appearances_controller_decorator.rb b/app/controllers/hyrax/admin/appearances_controller_decorator.rb new file mode 100644 index 000000000..287c27df1 --- /dev/null +++ b/app/controllers/hyrax/admin/appearances_controller_decorator.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v5.0.0rc2 to add selectable themes + +module Hyrax + module Admin + module AppearancesControllerDecorator + def show + # TODO: make selected font the font that show in select box + # TODO add body and headline font to the import url + add_breadcrumbs + @form = form_class.new + @fonts = [@form.headline_font, @form.body_font] + @home_theme_information = YAML.load_file(Hyku::Application.path_for('config/home_themes.yml')) + @show_theme_information = YAML.load_file(Hyku::Application.path_for('config/show_themes.yml')) + @home_theme_names = load_home_theme_names + @show_theme_names = load_show_theme_names + @search_themes = load_search_themes + + flash[:alert] = t('hyrax.admin.appearances.show.forms.custom_css.warning') + end + + def update + form_class.new(update_params).update! + + if update_params['default_collection_image'] + # Reindex all Collections and AdminSets to apply new default collection image + ReindexCollectionsJob.perform_later + ReindexAdminSetsJob.perform_later + end + + if update_params['default_work_image'] + # Reindex all Works to apply new default work image + ReindexWorksJob.perform_later + end + + redirect_to({ action: :show }, notice: t('.flash.success')) + end + + private + + def add_breadcrumbs + add_breadcrumb t(:'hyrax.controls.home'), root_path + add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path + add_breadcrumb t(:'hyrax.admin.sidebar.configuration'), '#' + add_breadcrumb t(:'hyrax.admin.sidebar.appearance'), request.path + end + + def load_home_theme_names + home_theme_names = [] + @home_theme_information.each do |theme, value_hash| + value_hash.each do |key, value| + home_theme_names << [value, theme] if key == 'name' + end + end + home_theme_names + end + + def load_show_theme_names + show_theme_names = [] + @show_theme_information.each do |theme, value_hash| + value_hash.each do |key, value| + show_theme_names << [value, theme] if key == 'name' + end + end + show_theme_names + end + + def load_search_themes + { + 'List view' => 'list_view', + 'Gallery view' => 'gallery_view' + } + end + end + end +end + +Hyrax::Admin::AppearancesController.prepend(Hyrax::Admin::AppearancesControllerDecorator) diff --git a/app/controllers/hyrax/admin/workflow_roles_controller.rb b/app/controllers/hyrax/admin/workflow_roles_controller.rb deleted file mode 100644 index 9e388f66e..000000000 --- a/app/controllers/hyrax/admin/workflow_roles_controller.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax v3.4.2 Expand to allow adding groups to workflow roles -module Hyrax - module Admin - class WorkflowRolesController < ApplicationController - before_action :require_permissions - with_themed_layout 'dashboard' - - def index - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t(:'hyrax.admin.workflow_roles.header'), hyrax.admin_workflow_roles_path - @presenter = WorkflowRolesPresenter.new - end - - def destroy - responsibility = Sipity::WorkflowResponsibility.find(params[:id]) - authorize! :destroy, responsibility - responsibility.destroy - redirect_to admin_workflow_roles_path - end - - # OVERRIDE: Add WorkflowResponsibilityGroupForm - def create - authorize! :create, Sipity::WorkflowResponsibility - - # Determine which form it is, user or group - form_params = params[:sipity_workflow_responsibility] - form = if form_params[:user_id].present? - Forms::WorkflowResponsibilityForm.new(form_params) - else - Forms::WorkflowResponsibilityGroupForm.new(form_params) - end - - begin - form.save! - rescue ActiveRecord::RecordNotUnique - logger.info "Not unique *****\n\n\n" - end - redirect_to admin_workflow_roles_path - end - - private - - def require_permissions - authorize! :read, :admin_dashboard - end - end - end -end diff --git a/app/controllers/hyrax/contact_form_controller.rb b/app/controllers/hyrax/contact_form_controller.rb deleted file mode 100644 index a420f82d4..000000000 --- a/app/controllers/hyrax/contact_form_controller.rb +++ /dev/null @@ -1,131 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE: Hyrax v3.4.0 -# - add inject_theme_views method for theming -# - add homepage presenter for access to feature flippers -# - add access to content blocks in the show method -# - add @featured_collection_list to new method - -module Hyrax - class ContactFormController < ApplicationController - # OVERRIDE: Hyrax v3.4.0 Add for theming - # Adds Hydra behaviors into the application controller - include Blacklight::SearchContext - include Blacklight::SearchHelper - include Blacklight::AccessControls::Catalog - before_action :build_contact_form - layout 'homepage' - # OVERRIDE: Adding inject theme views method for theming - around_action :inject_theme_views - class_attribute :model_class - self.model_class = Hyrax::ContactForm - before_action :setup_negative_captcha, only: %i[new create] - # OVERRIDE: Hyrax v3.4.0 Add for theming - # The search builder for finding recent documents - # Override of Blacklight::RequestBuilders - def search_builder_class - Hyrax::HomepageSearchBuilder - end - - # OVERRIDE: Hyrax v3.4.0 Add for theming - class_attribute :presenter_class - # OVERRIDE: Hyrax v3.4.0 Add for theming - self.presenter_class = Hyrax::HomepagePresenter - - helper Hyrax::ContentBlockHelper - - def new - # OVERRIDE: Hyrax v3.4.0 Add for theming - @presenter = presenter_class.new(current_ability, collections) - @featured_researcher = ContentBlock.for(:researcher) - @marketing_text = ContentBlock.for(:marketing) - @home_text = ContentBlock.for(:home_text) - @featured_work_list = FeaturedWorkList.new - # OVERRIDE: Hyrax 3.4.0 add @featured_collection_list - @featured_collection_list = FeaturedCollectionList.new - @announcement_text = ContentBlock.for(:announcement) - end - - def create - # not spam, form is valid, and captcha is valid - @captcha.values[:category] = params[:contact_form][:category] - @captcha.values[:contact_method] = params[:contact_form][:contact_method] - @captcha.values[:subject] = params[:contact_form][:subject] - @contact_form = model_class.new(@captcha.values) - if @contact_form.valid? && @captcha.valid? - ContactMailer.contact(@contact_form).deliver_now - flash.now[:notice] = 'Thank you for your message!' - after_deliver - else - flash.now[:error] = 'Sorry, this message was not sent successfully. ' + - @contact_form.errors.full_messages.map(&:to_s).join(", ") + - "" + @captcha.error - end - render :new - rescue RuntimeError => exception - handle_create_exception(exception) - end - - def handle_create_exception(exception) - logger.error("Contact form failed to send: #{exception.inspect}") - flash.now[:error] = 'Sorry, this message was not delivered.' - render :new - end - - # Override this method if you want to perform additional operations - # when a email is successfully sent, such as sending a confirmation - # response to the user. - def after_deliver; end - - private - - def build_contact_form - @contact_form = model_class.new(contact_form_params) - end - - def contact_form_params - return {} unless params.key?(:contact_form) - params.require(:contact_form).permit(:contact_method, :category, :name, :email, :subject, :message) - end - - # OVERRIDE: return collections for theming - def collections(rows: 6) - builder = Hyrax::CollectionSearchBuilder.new(self) - .rows(rows) - response = repository.search(builder) - response.documents - rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest - [] - end - - # OVERRIDE: Adding to prepend the theme views into the view_paths - def inject_theme_views - if home_page_theme && home_page_theme != 'default_home' - original_paths = view_paths - home_theme_view_path = Rails.root.join('app', 'views', "themes", home_page_theme.to_s) - prepend_view_path(home_theme_view_path) - yield - # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. - view_paths=(original_paths) - # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses - else - yield - end - end - - def setup_negative_captcha - @captcha = NegativeCaptcha.new( - # A secret key entered in environment.rb. 'rake secret' will give you a good one. - secret: ENV.fetch('NEGATIVE_CAPTCHA_SECRET', 'default-value-change-me'), - spinner: request.remote_ip, - # Whatever fields are in your form - fields: %i[name email subject message], - # If you wish to override the default CSS styles (position: absolute; left: -2000px;) - # used to position the fields off-screen - css: "display: none", - params: params - ) - end - end -end diff --git a/app/controllers/hyrax/contact_form_controller_decorator.rb b/app/controllers/hyrax/contact_form_controller_decorator.rb new file mode 100644 index 000000000..63d7bef19 --- /dev/null +++ b/app/controllers/hyrax/contact_form_controller_decorator.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +# OVERRIDE: Hyrax v5.0.0rc2 +# - adds inject_theme_views method for theming +# - adds homepage presenter for access to feature flippers +# - adds access to content blocks in the show method +# - adds @featured_collection_list to new method +# - adds captcha +module Hyrax + module ContactFormControllerDecorator + extend ActiveSupport::Concern + + # OVERRIDE: Add for theming + # Adds Hydra behaviors into the application controller + include Blacklight::SearchContext + include Blacklight::AccessControls::Catalog + + prepended do + # OVERRIDE: Adding inject theme views method for theming + around_action :inject_theme_views + before_action :setup_negative_captcha, only: %i[new create] + + # OVERRIDE: Add for theming + class_attribute :presenter_class + self.presenter_class = Hyrax::HomepagePresenter + + helper Hyrax::ContentBlockHelper + end + + # OVERRIDE: Add for theming + # The search builder for finding recent documents + # Override of Blacklight::RequestBuilders + def search_builder_class + Hyrax::HomepageSearchBuilder + end + + def new + # OVERRIDE: Add for theming + @presenter = presenter_class.new(current_ability, collections) + @featured_researcher = ContentBlock.for(:researcher) + @marketing_text = ContentBlock.for(:marketing) + @home_text = ContentBlock.for(:home_text) + @featured_work_list = FeaturedWorkList.new + @featured_collection_list = FeaturedCollectionList.new + @announcement_text = ContentBlock.for(:announcement) + end + + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + def create + # not spam and a valid form + # Override to include captcha + @captcha.values[:category] = params[:contact_form][:category] + @captcha.values[:contact_method] = params[:contact_form][:contact_method] + @captcha.values[:subject] = params[:contact_form][:subject] + @contact_form = model_class.new(@captcha.values) + if @contact_form.valid? && @captcha.valid? + ContactMailer.contact(@contact_form).deliver_now + flash.now[:notice] = 'Thank you for your message!' + after_deliver + else + flash.now[:error] = 'Sorry, this message was not sent successfully. ' + + @contact_form.errors.full_messages.map(&:to_s).join(", ") + end + render :new + rescue RuntimeError => exception + handle_create_exception(exception) + end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + + private + + # OVERRIDE: return collections for theming + # Return 6 collections, sorts by title + def collections(rows: 6) + Hyrax::CollectionsService.new(self).search_results do |builder| + builder.rows(rows) + builder.merge(sort: "title_ssi") + end + rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest + [] + end + + # OVERRIDE: Adding to prepend the theme views into the view_paths + def inject_theme_views + if home_page_theme && home_page_theme != 'default_home' + original_paths = view_paths + Hyku::Application.theme_view_path_roots.each do |root| + home_theme_view_path = File.join(root, 'app', 'views', "themes", home_page_theme.to_s) + prepend_view_path(home_theme_view_path) + end + yield + # rubocop:disable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + # Do NOT change this line. This is calling the Rails view_paths=(paths) method and not a variable assignment. + view_paths=(original_paths) + # rubocop:enable Lint/UselessAssignment, Layout/SpaceAroundOperators, Style/RedundantParentheses + else + yield + end + end + + def setup_negative_captcha + @captcha = NegativeCaptcha.new( + # A secret key entered in environment.rb. 'rake secret' will give you a good one. + secret: ENV.fetch('NEGATIVE_CAPTCHA_SECRET', 'default-value-change-me'), + spinner: request.remote_ip, + # Whatever fields are in your form + fields: %i[name email subject message], + # If you wish to override the default CSS styles (position: absolute; left: -2000px;) + # used to position the fields off-screen + css: "display: none", + params: + ) + end + end +end + +Hyrax::ContactFormController.prepend(Hyrax::ContactFormControllerDecorator) diff --git a/app/controllers/hyrax/content_blocks_controller.rb b/app/controllers/hyrax/content_blocks_controller.rb deleted file mode 100644 index 60edc5286..000000000 --- a/app/controllers/hyrax/content_blocks_controller.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax v3.4.0 to add home_text to permitted_params - Adding themes -module Hyrax - class ContentBlocksController < ApplicationController - load_and_authorize_resource - with_themed_layout 'dashboard' - - def edit - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t(:'hyrax.admin.sidebar.configuration'), '#' - add_breadcrumb t(:'hyrax.admin.sidebar.content_blocks'), hyrax.edit_content_blocks_path - end - - def update - respond_to do |format| - if @content_block.update(value: update_value_from_params) - format.html { redirect_to hyrax.edit_content_blocks_path, notice: t(:'hyrax.content_blocks.updated') } - else - format.html { render :edit } - end - end - end - - private - - # override hyrax v2.9.0 added the home_text content block to permitted_params - Adding Themes - def permitted_params - params.require(:content_block).permit(:marketing, - :announcement, - :home_text, - :researcher) - end - - # When a request comes to the controller, it will be for one and - # only one of the content blocks. Params always looks like: - # {'about_page' => 'Here is an awesome about page!'} - # So reach into permitted params and pull out the first value. - def update_value_from_params - permitted_params.values.first - end - end -end diff --git a/app/controllers/hyrax/content_blocks_controller_decorator.rb b/app/controllers/hyrax/content_blocks_controller_decorator.rb new file mode 100644 index 000000000..bcca43e36 --- /dev/null +++ b/app/controllers/hyrax/content_blocks_controller_decorator.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v5.0.0rc2 to add home_text to permitted_params - Adding themes + +module Hyrax + module ContentBlocksControllerDecorator + private + + def permitted_params + params.require(:content_block).permit(:marketing, + :announcement, + :home_text, + :homepage_about_section_heading, + :homepage_about_section_content, + :researcher) + end + end +end + +Hyrax::ContentBlocksController.prepend Hyrax::ContentBlocksControllerDecorator diff --git a/app/controllers/hyrax/dashboard/collections_controller.rb b/app/controllers/hyrax/dashboard/collections_controller.rb deleted file mode 100644 index 762252645..000000000 --- a/app/controllers/hyrax/dashboard/collections_controller.rb +++ /dev/null @@ -1,737 +0,0 @@ -# OVERRIDE Hyrax v3.4.2 -# - Fix file upload in logo and banner -# - Use work titles for collection thumbnail select & to add an option to reset to the default thumbnail -module Hyrax - module Dashboard - ## Shows a list of all collections to the admins - class CollectionsController < Hyrax::My::CollectionsController - include Blacklight::AccessControls::Catalog - include Blacklight::Base - - configure_blacklight do |config| - config.search_builder_class = Hyrax::Dashboard::CollectionsSearchBuilder - end - - include BreadcrumbsForCollections - with_themed_layout 'dashboard' - - before_action :filter_docs_with_read_access!, except: %i[show edit] - before_action :remove_select_something_first_flash, except: :show - - include Hyrax::Collections::AcceptsBatches - - # include the render_check_all view helper method - helper Hyrax::BatchEditsHelper - # include the display_trophy_link view helper method - helper Hyrax::TrophyHelper - - # Catch permission errors - rescue_from Hydra::AccessDenied, CanCan::AccessDenied, with: :deny_collection_access - - # actions: index, create, new, edit, show, update, destroy, permissions, citation - before_action :authenticate_user!, except: [:index] - - class_attribute :presenter_class, - :form_class, - :single_item_search_builder_class, - :membership_service_class - - self.presenter_class = Hyrax::CollectionPresenter - - self.form_class = Hyrax::Forms::CollectionForm - - # The search builder to find the collection - self.single_item_search_builder_class = SingleCollectionSearchBuilder - # The search builder to find the collections' members - self.membership_service_class = Collections::CollectionMemberSearchService - - load_and_authorize_resource except: [:index, :create], - instance_name: :collection, - class: Hyrax.config.collection_model - - def deny_collection_access(exception) - if exception.action == :edit - redirect_to(url_for(action: 'show'), alert: 'You do not have sufficient privileges to edit this document') - elsif current_user&.persisted? - redirect_to root_url, alert: exception.message - else - session['user_return_to'] = request.url - redirect_to main_app.new_user_session_url, alert: exception.message - end - end - - def new - # Coming from the UI, a collection type id should always be present. Coming from the API, if a collection type id is not specified, - # use the default collection type (provides backward compatibility with versions < Hyrax 2.1.0) - collection_type_id = params[:collection_type_id].presence || default_collection_type.id - @collection.collection_type_gid = CollectionType.find(collection_type_id).to_global_id - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t('.header', type_title: collection_type.title), request.path - @collection.try(:apply_depositor_metadata, current_user.user_key) - form - end - - def show - # unused assignment to be removed in 4.0.0 - @banner_file = presenter.banner_file if collection_type.brandable? - - presenter - query_collection_members - end - - def edit - form - collection_type - # Gets original filename of an uploaded thumbnail. See #update - if ::SolrDocument.find(@collection.id).thumbnail_path.include? "uploaded_collection_thumbnails" and uploaded_thumbnail? - @thumbnail_filename = File.basename(uploaded_thumbnail_files.reject { |f| File.basename(f).include? @collection.id }.first) - end - end - - def uploaded_thumbnail? - uploaded_thumbnail_files.any? - end - - def uploaded_thumbnail_files - Dir["#{UploadedCollectionThumbnailPathService.upload_dir(@collection)}/*"] - end - - def after_create - Deprecation.warn("Method `#after_create` will be removed in Hyrax 4.0.") - after_create_response # call private method for processing - end - - def after_create_error - Deprecation.warn("Method `#after_create_error` will be removed in Hyrax 4.0.") - after_create_errors("") # call private method for processing - end - - def create - # Manual load and authorize necessary because Cancan will pass in all - # form attributes. When `permissions_attributes` are present the - # collection is saved without a value for `has_model.` - @collection = Hyrax.config.collection_class.new - authorize! :create, @collection - - case @collection - when ActiveFedora::Base - create_active_fedora_collection - else - create_valkyrie_collection - end - end - - def after_update - Deprecation.warn("Method `#after_update` will be removed in Hyrax 4.0.") - after_update_response # call private method for processing - end - - def after_update_error - Deprecation.warn("Method `#after_update_error` will be removed in Hyrax 4.0.") - after_update_errors(@collection.errors) # call private method for processing - end - - def update - # OVERRIDE: ensure user is allowed to change visibility - authorize! :manage_discovery, @collection if collection_params[:visibility].present? && @collection.visibility != collection_params[:visibility] - - case @collection - when ActiveFedora::Base - update_active_fedora_collection - else - update_valkyrie_collection - end - end - - def process_branding - process_banner_input - process_logo_input - # TODO does this still work? - process_uploaded_thumbnail(params[:collection][:thumbnail_upload]) if params[:collection][:thumbnail_upload] - end - - # Deletes any previous thumbnails. The thumbnail indexer (see services/hyrax/indexes_thumbnails) - # checks if an uploaded thumbnail exists in the public folder before indexing the thumbnail path. - def delete_uploaded_thumbnail - FileUtils.rm_rf(uploaded_thumbnail_files) - @collection.update_index - - respond_to do |format| - format.html - format.js # renders delete_uploaded_thumbnail.js.erb, which updates _current_thumbnail.html.erb - end - end - - def after_destroy(_id) - # leaving id to avoid changing the method's parameters prior to release - respond_to do |format| - format.html do - redirect_to hyrax.my_collections_path, - notice: t('hyrax.dashboard.my.action.collection_delete_success') - end - format.json { head :no_content, location: hyrax.my_collections_path } - end - end - - def after_destroy_error(id) - respond_to do |format| - format.html do - flash[:notice] = t('hyrax.dashboard.my.action.collection_delete_fail') - render :edit, status: :unprocessable_entity - end - format.json { render json: { id: id }, status: :unprocessable_entity, location: dashboard_collection_path(@collection) } - end - end - - def destroy - case @collection - when Valkyrie::Resource - valkyrie_destroy - else - if @collection.destroy - after_destroy(params[:id]) - else - after_destroy_error(params[:id]) - end - end - rescue StandardError => err - Rails.logger.error(err) - after_destroy_error(params[:id]) - end - - def collection - action_name == 'show' ? @presenter : @collection - end - - # Renders a JSON response with a list of files in this collection - # This is used by the edit form to populate the thumbnail_id dropdown - # OVERRIDE: Hyrax 2.9 to use work titles for collection thumbnail select & to add an option to reset to the default thumbnail - def files - params[:q] = '' unless params[:q] - builder = Hyrax::CollectionMemberSearchBuilder.new(scope: self, collection: collection, search_includes_models: :works) - # get the default work image because we do not want to show any works in this dropdown that only have the default work image. this indicates that they have no files attached, and will throw an error if selected. - default_work_thumbnail_path = Site.instance.default_work_image&.url.presence || ActionController::Base.helpers.image_path('default.png') - work_with_no_files_thumbnail_path = ActionController::Base.helpers.image_path('work.png') - response = repository.search(builder.where(params[:q]).query) - # only return the works that have files, because these will be the only ones with a viable thumbnail - result = response.documents.reject { |document| document["thumbnail_path_ss"].blank? || document["thumbnail_path_ss"].include?(default_work_thumbnail_path) || document["thumbnail_path_ss"].include?(work_with_no_files_thumbnail_path) }.map do |document| - { id: document["thumbnail_path_ss"].split('/').last.gsub(/\?.*/, ''), text: document["title_tesim"].first } - end - reset_thumbnail_option = { - id: '', - text: 'Default thumbnail' - } - result << reset_thumbnail_option - render json: result - end - - private - - def create_active_fedora_collection - # Coming from the UI, a collection type gid should always be present. Coming from the API, if a collection type gid is not specified, - # use the default collection type (provides backward compatibility with versions < Hyrax 2.1.0) - @collection.collection_type_gid = params[:collection_type_gid].presence || default_collection_type.to_global_id - @collection.attributes = collection_params.except(:members, :parent_id, :collection_type_gid) - @collection.apply_depositor_metadata(current_user.user_key) - @collection.visibility = Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE unless @collection.discoverable? - if @collection.save - after_create_response - else - after_create_errors(@collection.errors) - end - end - - def create_valkyrie_collection - return after_create_errors(form_err_msg(form)) unless form.validate(collection_params) - - result = - transactions['change_set.create_collection'] - .with_step_args( - 'change_set.set_user_as_depositor' => { user: current_user }, - 'change_set.add_to_collections' => { collection_ids: Array(params[:parent_id]) }, - 'collection_resource.apply_collection_type_permissions' => { user: current_user } - ) - .call(form) - - @collection = result.value_or { return after_create_errors(result.failure.first) } - after_create_response - end - - def update_active_fedora_collection - process_member_changes - process_branding - - @collection.visibility = Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE unless @collection.discoverable? - # we don't have to reindex the full graph when updating collection - @collection.try(:reindex_extent=, Hyrax::Adapters::NestingIndexAdapter::LIMITED_REINDEX) - if @collection.update(collection_params.except(:members)) - after_update_response - else - after_update_errors(@collection.errors) - end - end - - def update_valkyrie_collection - return after_update_errors(form_err_msg(form)) unless form.validate(collection_params) - - result = transactions['change_set.update_collection'] - .with_step_args( - 'collection_resource.save_collection_banner' => { update_banner_file_ids: params["banner_files"], - banner_unchanged_indicator: params["banner_unchanged"] }, - 'collection_resource.save_collection_logo' => { update_logo_file_ids: params["logo_files"], - alttext_values: params["alttext"], - linkurl_values: params["linkurl"] } - ) - .call(form) - @collection = result.value_or { return after_update_errors(result.failure.first) } - - process_member_changes - after_update_response - end - - def valkyrie_destroy - if transactions['collection_resource.destroy'].call(@collection).successful? - after_destroy(params[:id]) - else - after_destroy_error(params[:id]) - end - end - - def form_err_msg(form) - errmsg = [] - form.errors.messages.each do |fld, err| - errmsg << "#{fld} #{err.to_sentence}" - end - errmsg.to_sentence - end - - def default_collection_type - Hyrax::CollectionType.find_or_create_default_collection_type - end - - def default_collection_type_gid - default_collection_type.to_global_id.to_s - end - - def collection_type - @collection_type ||= CollectionType.find_by_gid!(collection.collection_type_gid) - end - - def link_parent_collection(parent_id) - child = collection.respond_to?(:valkyrie_resource) ? collection.valkyrie_resource : collection - Hyrax::Collections::CollectionMemberService.add_member(collection_id: parent_id, - new_member: child, - user: current_user) - end - - def uploaded_files(uploaded_file_ids) - return [] if uploaded_file_ids.empty? - UploadedFile.find(uploaded_file_ids) - end - - def update_referer - return edit_dashboard_collection_path(@collection) + (params[:referer_anchor] || '') if params[:stay_on_edit] - dashboard_collection_path(@collection) - end - - # branding specific methods - def process_banner_input - return update_existing_banner if params["banner_unchanged"] == "true" - remove_banner - uploaded_file_ids = params["banner_files"] - banner_text = params["banner_text"]&.first - add_new_banner(uploaded_file_ids, banner_text) if uploaded_file_ids - end - - def update_existing_banner - banner_info = CollectionBrandingInfo.where(collection_id: @collection.id.to_s).where(role: "banner") - banner_info.first.alt_text = params["banner_text"].first - banner_info.first.save(banner_info.first.local_path, false) - end - - def add_new_banner(uploaded_file_ids, banner_text) - f = uploaded_files(uploaded_file_ids).first - ## OVERRIDE Hyrax 3.4.0 - process locations - file_location = process_file_location(f) - - banner_info = CollectionBrandingInfo.new( - collection_id: @collection.id, - filename: File.split(f.file_url).last, - role: "banner", - alt_txt: banner_text, - target_url: "" - ) - ## OVERRIDE Hyrax 3.4.0 - process locations - banner_info.save file_location - end - - def remove_banner - banner_info = CollectionBrandingInfo.where(collection_id: @collection.id.to_s).where(role: "banner") - banner_info&.delete_all - end - - def update_logo_info(uploaded_file_id, alttext, linkurl) - logo_info = CollectionBrandingInfo.where(collection_id: @collection.id.to_s).where(role: "logo").where(local_path: uploaded_file_id.to_s) - logo_info.first.alt_text = alttext - logo_info.first.target_url = linkurl - logo_info.first.local_path = uploaded_file_id - logo_info.first.save(uploaded_file_id, false) - end - - def create_logo_info(uploaded_file_id, alttext, linkurl) - file = uploaded_files(uploaded_file_id) - file_location = process_file_location(file) # OVERRIDE Hyrax 3.4.0 to clean file location - - logo_info = CollectionBrandingInfo.new( - collection_id: @collection.id, - filename: File.split(file.file_url).last, - role: "logo", - alt_txt: alttext, - target_url: linkurl - ) - logo_info.save file_location - logo_info - end - - def remove_redundant_files(public_files) - # remove any public ones that were not included in the selection. - logos_info = CollectionBrandingInfo.where(collection_id: @collection.id.to_s).where(role: "logo") - logos_info.each do |logo_info| - logo_info.delete(logo_info.local_path) unless public_files.include? logo_info.local_path - logo_info.destroy unless public_files.include? logo_info.local_path - end - end - - def process_logo_records(uploaded_file_ids) - public_files = [] - uploaded_file_ids.each_with_index do |ufi, i| - # If the user has chosen a new logo, the ufi will be an integer - # If the logo was previously chosen, the ufi will be a path - # If it is a path, update the rec, else create a new rec - if !ufi.match(/\D/).nil? - update_logo_info(ufi, params["alttext"][i], verify_linkurl(params["linkurl"][i])) - public_files << ufi - else # brand new one, insert in the database - logo_info = create_logo_info(ufi, params["alttext"][i], verify_linkurl(params["linkurl"][i])) - public_files << logo_info.local_path - end - end - public_files - end - - def process_logo_input - uploaded_file_ids = params["logo_files"] - public_files = [] - - if uploaded_file_ids.nil? - remove_redundant_files public_files - return - end - - public_files = process_logo_records uploaded_file_ids - remove_redundant_files public_files - end - - # run a solr query to get the collections the user has access to edit - # @return [Array] a list of the user's collections - def find_collections_for_form - Hyrax::CollectionsService.new(self).search_results(:edit) - end - - def remove_select_something_first_flash - flash.delete(:notice) if flash.notice == 'Select something first' - end - - def presenter - @presenter ||= presenter_class.new(curation_concern, current_ability) - end - - def curation_concern - # Query Solr for the collection. - # run the solr query to find the collection members - response, _docs = single_item_search_service.search_results - curation_concern = response.documents.first - raise CanCan::AccessDenied unless curation_concern - curation_concern - end - - def single_item_search_service - Hyrax::SearchService.new(config: blacklight_config, user_params: params.except(:q, :page), scope: self, search_builder_class: single_item_search_builder_class) - end - - # Instantiates the search builder that builds a query for a single item - # this is useful in the show view. - def single_item_search_builder - search_service.search_builder - end - deprecation_deprecate :single_item_search_builder - - def collection_params - if Hyrax.config.collection_class < ActiveFedora::Base - @participants = extract_old_style_permission_attributes(params[:collection]) - form_class.model_attributes(params[:collection]) - else - params.permit(collection: {})[:collection] - .merge(params.permit(:collection_type_gid) - .with_defaults(collection_type_gid: default_collection_type_gid)) - .merge(member_of_collection_ids: Array(params[:parent_id])) - end - end - - def extract_old_style_permission_attributes(attributes) - # TODO: REMOVE in 3.0 - part of deprecation of permission attributes - permissions = attributes.delete("permissions_attributes") - return [] unless permissions - Deprecation.warn(self, "Passing in permissions_attributes parameter with a new collection is deprecated and support will be removed from Hyrax 3.0. " \ - "Use Hyrax::PermissionTemplate instead to grant Manage, Deposit, or View access.") - participants = [] - permissions.each do |p| - access = access(p) - participants << { agent_type: agent_type(p), agent_id: p["name"], access: access } if access - end - participants - end - - def agent_type(permission) - # TODO: REMOVE in 3.0 - part of deprecation of permission attributes - return 'group' if permission["type"] == 'group' - 'user' - end - - def access(permission) - # TODO: REMOVE in 3.0 - part of deprecation of permission attributes - return Hyrax::PermissionTemplateAccess::MANAGE if permission["access"] == 'edit' - return Hyrax::PermissionTemplateAccess::VIEW if permission["access"] == 'read' - end - - def process_member_changes - case params[:collection][:members] - when 'add' then add_members_to_collection - when 'remove' then remove_members_from_collection - when 'move' then move_members_between_collections - end - end - - def add_members_to_collection(collection = nil, collection_id: nil) - collection_id ||= (collection.try(:id) || @collection.id) - - Hyrax::Collections::CollectionMemberService - .add_members_by_ids(collection_id: collection_id, - new_member_ids: batch, - user: current_user) - end - - def remove_members_from_collection - Hyrax::Collections::CollectionMemberService - .remove_members_by_ids(collection_id: @collection.id, - member_ids: batch, - user: current_user) - end - - def move_members_between_collections - remove_members_from_collection - add_members_to_collection(collection_id: params[:destination_collection_id]) - - destination_title = - Hyrax.query_service.find_by(id: params[:destination_collection_id]).title.first || - params[:destination_collection_id] - flash[:notice] = "Successfully moved #{batch.count} files to #{destination_title} Collection." - rescue StandardError => err - Rails.logger.error(err) - destination_title = - Hyrax.query_service.find_by(id: params[:destination_collection_id]).title.first || - destination_id - flash[:error] = "An error occured. Files were not moved to #{destination_title} Collection." - end - - # Include 'catalog' and 'hyrax/base' in the search path for views, while prefering - # our local paths. Thus we are unable to just override `self.local_prefixes` - def _prefixes - @_prefixes ||= super + ['catalog', 'hyrax/base'] - end - - def ensure_admin! - # Even though the user can view this collection, they may not be able to view - # it on the admin page. - authorize! :read, :admin_dashboard - end - - def search_action_url(*args) - hyrax.dashboard_collections_url(*args) - end - - def form - @form ||= - case @collection - when Valkyrie::Resource - form = Hyrax::Forms::ResourceForm.for(@collection) - form.prepopulate! - form - else - form_class.new(@collection, current_ability, repository) - end - end - - def set_default_permissions - additional_grants = @participants # Grants converted from older versions (< Hyrax 2.1.0) where share was edit or read access instead of managers, depositors, and viewers - Collections::PermissionsCreateService.create_default(collection: @collection, creating_user: current_user, grants: additional_grants) - end - - def query_collection_members - member_works - member_subcollections if collection_type.nestable? - parent_collections if collection_type.nestable? && action_name == 'show' - end - - # Instantiate the membership query service - def collection_member_service - @collection_member_service ||= membership_service_class.new(scope: self, collection: collection, params: params_for_query) - end - - def member_works - @response = collection_member_service.available_member_works - @member_docs = @response.documents - @members_count = @response.total - end - - def member_subcollections - results = collection_member_service.available_member_subcollections - @subcollection_solr_response = results - @subcollection_docs = results.documents - @subcollection_count = @presenter.nil? ? 0 : @subcollection_count = @presenter.subcollection_count = results.total - end - - def parent_collections - page = params[:parent_collection_page].to_i - query = Hyrax::Collections::NestedCollectionQueryService - collection.parent_collections = query.parent_collections(child: collection_object, scope: self, page: page) - end - - def collection_object - @collection - end - - # You can override this method if you need to provide additional - # inputs to the search builder. For example: - # search_field: 'all_fields' - # @return