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 the inputs required for the collection member search builder - def params_for_query - params.merge(q: params[:cq]) - end - - # Only accept HTTP|HTTPS urls; - # @return the url - def verify_linkurl(linkurl) - url = Loofah.scrub_fragment(linkurl, :prune).to_s - url if valid_url?(url) - end - - def valid_url?(url) - (url =~ URI.regexp(['http', 'https'])) - end - - def after_create_response - if @collection.is_a?(ActiveFedora::Base) - form - set_default_permissions - # if we are creating the new collection as a subcollection (via the nested collections controller), - # we pass the parent_id through a hidden field in the form and link the two after the create. - link_parent_collection(params[:parent_id]) unless params[:parent_id].nil? - end - respond_to do |format| - Hyrax::SolrService.commit - format.html { redirect_to edit_dashboard_collection_path(@collection), notice: t('hyrax.dashboard.my.action.collection_create_success') } - format.json { render json: @collection, status: :created, location: dashboard_collection_path(@collection) } - end - add_members_to_collection unless batch.empty? - end - - def after_create_errors_for_active_fedora(errors) - form - respond_to do |format| - format.html do - flash[:error] = errors.to_s - render action: 'new' - end - format.json { render json: @collection.errors, status: :unprocessable_entity } - end - end - - def after_create_errors(errors) # for valkyrie - return after_create_errors_for_active_fedora(errors) if @collection.is_a? ActiveFedora::Base - respond_to do |wants| - wants.html do - flash[:error] = errors.to_s - render 'new', status: :unprocessable_entity - end - wants.json do - render_json_response(response_type: :unprocessable_entity, options: { errors: errors }) - end - end - end - - def after_update_response - respond_to do |format| - format.html { redirect_to update_referer, notice: t('hyrax.dashboard.my.action.collection_update_success') } - format.json { render json: @collection, status: :updated, location: dashboard_collection_path(@collection) } - end - end - - def after_update_errors_for_active_fedora(errors) - form - respond_to do |format| - format.html do - flash[:error] = errors.to_s - render action: 'edit' - end - format.json { render json: @collection.errors, status: :unprocessable_entity } - end - end - - def after_update_errors(errors) # for valkyrie - return after_update_errors_for_active_fedora(errors) if @collection.is_a? ActiveFedora::Base - respond_to do |wants| - wants.html do - flash[:error] = errors.to_s - render 'edit', status: :unprocessable_entity - end - wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: errors }) } - end - end - - def process_uploaded_thumbnail(uploaded_file) - dir_name = UploadedCollectionThumbnailPathService.upload_dir(@collection) - saved_file = Rails.root.join(dir_name, uploaded_file.original_filename) - # Create directory if it doesn't already exist - unless File.directory?(dir_name) - FileUtils.mkdir_p(dir_name) - else # clear contents - delete_uploaded_thumbnail - end - File.open(saved_file, 'wb') do |file| - file.write(uploaded_file.read) - end - image = MiniMagick::Image.open(saved_file) - # Save two versions of the image: one for homepage feature cards and one for regular thumbnail - image.resize('500x900').format("jpg").write("#{dir_name}/#{@collection.id}_card.jpg") - image.resize('150x300').format("jpg").write("#{dir_name}/#{@collection.id}_thumbnail.jpg") - File.chmod(0664,"#{dir_name}/#{@collection.id}_thumbnail.jpg") - File.chmod(0664,"#{dir_name}/#{@collection.id}_card.jpg") - end - - ## OVERRIDE Hyrax 3.4.0 handle file locations - def process_file_location(f) - if f.file_url =~ /^http/ - f.file.download!(f.file_url) - f.file_url - elsif f.file_url =~ %r{^\/} - f.file.path - else - f.file_url - end - end - ## END OVERRIDE - end - end -end diff --git a/app/controllers/hyrax/dashboard/collections_controller_decorator.rb b/app/controllers/hyrax/dashboard/collections_controller_decorator.rb new file mode 100644 index 000000000..dcc1fb94b --- /dev/null +++ b/app/controllers/hyrax/dashboard/collections_controller_decorator.rb @@ -0,0 +1,182 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v5.0.0rc2 +# - 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 + # rubocop:disable Metrics/ModuleLength + module CollectionsControllerDecorator + def edit + form + collection_type + # Gets original filename of an uploaded thumbnail. See #update + return unless ::SolrDocument.find(@collection.id).thumbnail_path.include?("uploaded_collection_thumbnails") && uploaded_thumbnail? + @thumbnail_filename = File.basename(uploaded_thumbnail_files.reject { |f| File.basename(f).include? @collection.id }.first) + end + + def uploaded_thumbnail? + uploaded_thumbnail_files.any? + end + + def uploaded_thumbnail_files + Dir["#{UploadedCollectionThumbnailPathService.upload_dir(@collection)}/*"] + 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] + + super + end + + def process_branding + super + + # 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 + + # 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 + # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def files + params[:q] = '' unless params[:q] + builder = Hyrax::CollectionMemberSearchBuilder.new(scope: self, 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 do |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) + # rubocop:disable Style/MultilineBlockChain + end.map do |document| + # rubocop:enable Style/MultilineBlockChain + { 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 + # rubocop:enable Metrics/MethodLength, Metrics/AbcSize + + private + + # 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 v5.0.0rc2 - 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 v5.0.0rc2 - process locations + banner_info.save file_location + end + + def create_logo_info(uploaded_file_id, alttext, linkurl) + file = uploaded_files(uploaded_file_id) + file_location = process_file_location(file) # OVERRIDE Hyrax v5.0.0rc2 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 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 + + # rubocop:disable Metrics/MethodLength + def process_uploaded_thumbnail(uploaded_file) + dir_name = UploadedCollectionThumbnailPathService.upload_dir(@collection) + saved_file = Rails.root.join(dir_name, uploaded_file.original_filename) + # Create directory if it doesn't already exist + if File.directory?(dir_name) # clear contents + delete_uploaded_thumbnail + else + FileUtils.mkdir_p(dir_name) + end + File.open(saved_file, 'wb') do |file| + file.write(uploaded_file.read) + end + image = MiniMagick::Image.open(saved_file) + # Save two versions of the image: one for homepage feature cards and one for regular thumbnail + image.resize('500x900').format("jpg").write("#{dir_name}/#{@collection.id}_card.jpg") + image.resize('150x300').format("jpg").write("#{dir_name}/#{@collection.id}_thumbnail.jpg") + File.chmod(0o664, "#{dir_name}/#{@collection.id}_thumbnail.jpg") + File.chmod(0o664, "#{dir_name}/#{@collection.id}_card.jpg") + end + # rubocop:enable Metrics/MethodLength + + ## OVERRIDE Hyrax v5.0.0rc2 handle file locations + def process_file_location(f) + if /^http/.match?(f.file_url) + f.file.download!(f.file_url) + f.file_url + elsif %r{^\/}.match?(f.file_url) + f.file.path + else + f.file_url + end + end + ## END OVERRIDE + end + end +end + +Hyrax::Dashboard::CollectionsController.prepend(Hyrax::Dashboard::CollectionsControllerDecorator) diff --git a/app/controllers/hyrax/featured_collection_lists_controller.rb b/app/controllers/hyrax/featured_collection_lists_controller.rb index 29a9e3802..d34251735 100644 --- a/app/controllers/hyrax/featured_collection_lists_controller.rb +++ b/app/controllers/hyrax/featured_collection_lists_controller.rb @@ -13,8 +13,8 @@ def create private - def list_params - params.require(:featured_collection_list).permit(featured_collections_attributes: %i[id order]) - end + def list_params + params.require(:featured_collection_list).permit(featured_collections_attributes: %i[id order]) + end end end diff --git a/app/controllers/hyrax/generic_works_controller.rb b/app/controllers/hyrax/generic_works_controller.rb index 243dfcbfd..9831ea89a 100644 --- a/app/controllers/hyrax/generic_works_controller.rb +++ b/app/controllers/hyrax/generic_works_controller.rb @@ -7,6 +7,7 @@ module Hyrax class GenericWorksController < ApplicationController # Adds Hyrax behaviors to the controller. include Hyrax::WorksControllerBehavior + include Hyku::WorksControllerBehavior include Hyrax::BreadcrumbsForWorks self.curation_concern_type = ::GenericWork diff --git a/app/controllers/hyrax/homepage_controller.rb b/app/controllers/hyrax/homepage_controller.rb index a38eda845..a19c16103 100644 --- a/app/controllers/hyrax/homepage_controller.rb +++ b/app/controllers/hyrax/homepage_controller.rb @@ -1,27 +1,41 @@ # frozen_string_literal: true -# OVERRIDE: Hyrax v2.9.0 to add home_text content block to the index method - Adding themes -# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add facets to home page - inheriting from -# CatalogController rather than ApplicationController -# OVERRIDE: Hyrax v2.9.0 from Hyrax v2.9.0 to add inject_theme_views method for theming -# OVERRIDE: Hyrax v2.9.0 to add search_action_url method from Blacklight 6.23.0 to make facet links to go to /catalog -# OVERRIDE: Hyrax v2.9.0 to add .sort_by to return collections in alphabetical order by title on the homepage -# OVERRIDE: Hyrax v2.9.0 add all_collections page for IR theme -# OVERRIDE: Hyrax v2.9.0 to add facet counts for resource types for IR theme -# OVERRIDE: Hyrax v. 2.9.0 to add @featured_collection_list to index method +######################################################################################### +######################################################################################### +# +# +# HACK: We have copied over the Hyrax::HomepageController to address Hyku specific +# customizations. This controller needs significant refactoring and reconciliation +# with Hyrax prime. Note, we are inheriting differently than Hyrax does and +# there are other adjustments. +# +# +######################################################################################### +######################################################################################### + +# OVERRIDE: Hyrax v5.0.0 +# - add home_text content block to the index method - Adding themes +# - add inject_theme_views method for theming +# - add all_collections page for IR theme +# - add facet counts for resource types for IR theme + +# - add facets to home page - inheriting from CatalogController rather than ApplicationController +# - add search_action_url method from Blacklight 6.23.0 to make facet links to go to /catalog +# - add .sort_by to return collections in alphabetical order by title on the homepage +# - add @featured_collection_list to index method module Hyrax # Changed to inherit from CatalogController for home page facets class HomepageController < CatalogController # Adds Hydra behaviors into the application controller include Blacklight::SearchContext - include Blacklight::SearchHelper include Blacklight::AccessControls::Catalog + # OVERRIDE: account for Hyku themes around_action :inject_theme_views # The search builder for finding recent documents - # Override of Blacklight::RequestBuilders + # Override of Blacklight::RequestBuilders and default CatalogController behavior def search_builder_class Hyrax::HomepageSearchBuilder end @@ -31,21 +45,25 @@ def search_builder_class layout 'homepage' helper Hyrax::ContentBlockHelper - # override hyrax v2.9.0 added @home_text - Adding Themes + # rubocop:disable Metrics/MethodLength def index + # BEGIN copy Hyrax prime's Hyrax::HomepageController#index @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 here to add featured collection list - @featured_collection_list = FeaturedCollectionList.new @announcement_text = ContentBlock.for(:announcement) recent + # END copy + + # BEGIN OVERRIDE + # What follows is Hyku specific overrides + @home_text = ContentBlock.for(:home_text) # hyrax v3.5.0 added @home_text - Adding Themes + @featured_collection_list = FeaturedCollectionList.new # OVERRIDE here to add featured collection list + ir_counts if home_page_theme == 'institutional_repository' - # override hyrax v2.9.0 added for facets on homepage - Adding Themes - (@response, @document_list) = search_results(params) + (@response, @document_list) = search_service.search_results respond_to do |format| format.html { store_preferred_view } @@ -61,6 +79,7 @@ def index document_export_formats(format) end end + # rubocop:enable Metrics/MethodLength def browserconfig; end @@ -75,57 +94,70 @@ def all_collections # Added from Blacklight 6.23.0 to change url for facets on home page protected - # Default route to the search action (used e.g. in global partials). Override this method - # in a controller or in your ApplicationController to introduce custom logic for choosing - # which action the search form should use - def search_action_url(options = {}) - # Rails 4.2 deprecated url helpers accepting string keys for 'controller' or 'action' - main_app.search_catalog_path(options) - end + # Default route to the search action (used e.g. in global partials). Override this method + # in a controller or in your ApplicationController to introduce custom logic for choosing + # which action the search form should use + def search_action_url(options = {}) + # Rails 4.2 deprecated url helpers accepting string keys for 'controller' or 'action' + main_app.search_catalog_path(options) + end private - # Return 6 collections - def collections(rows: 6) - builder = Hyrax::CollectionSearchBuilder.new(self) - .rows(rows) - response = repository.search(builder) - # adding .sort_by to return collections in alphabetical order by title on the homepage - response.documents.sort_by(&:title) - rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest - [] + # 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 - def recent - # grab any recent documents - (_, @recent_documents) = search_results(q: '', sort: sort_field, rows: 6) - rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest - @recent_documents = [] + # override to show 6 recent items + def recent(rows: 6) + (_, @recent_documents) = search_service.search_results do |builder| + builder.rows(rows) + builder.merge(sort: sort_field) end + rescue Blacklight::Exceptions::ECONNREFUSED, Blacklight::Exceptions::InvalidRequest + @recent_documents = [] + end - # OVERRIDE: Hyrax v2.9.0 to add facet counts for resource types for IR theme - def ir_counts - @ir_counts = get_facet_field_response('resource_type_sim', {}, "f.resource_type_sim.facet.limit" => "-1") - end + def ir_counts + @ir_counts = search_service.facet_field_response('resource_type_sim', "f.resource_type_sim.facet.limit" => "-1") + end - def sort_field - "date_uploaded_dtsi desc" - end + # COPIED from Hyrax::HomepageController + def sort_field + "date_uploaded_dtsi desc" + end - # Add this method 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 + # Add this method 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 + + # add this method to vary blacklight config and user_params + def search_service(*_args) + Hyrax::SearchService.new( + config: ::CatalogController.new.blacklight_config, + user_params: params.except(:q, :page), + scope: self, + current_ability:, + search_builder_class: + ) + end end end diff --git a/app/controllers/hyrax/images_controller.rb b/app/controllers/hyrax/images_controller.rb index e37798964..ec45442aa 100644 --- a/app/controllers/hyrax/images_controller.rb +++ b/app/controllers/hyrax/images_controller.rb @@ -7,6 +7,7 @@ module Hyrax class ImagesController < ApplicationController # Adds Hyrax behaviors to the controller. include Hyrax::WorksControllerBehavior + include Hyku::WorksControllerBehavior include Hyrax::BreadcrumbsForWorks self.curation_concern_type = ::Image diff --git a/app/controllers/hyrax/my/works_controller_decorator.rb b/app/controllers/hyrax/my/works_controller_decorator.rb deleted file mode 100644 index df68ce1ca..000000000 --- a/app/controllers/hyrax/my/works_controller_decorator.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -## -# OVERRIDE Hyrax 3.5.0; when Hyrax hits v4.0.0 we can remove this. -# @see https://github.com/samvera/hyrax/pull/5972 -module Hyrax - module My - module WorksControllerDecorator - def collections_service - cloned = clone - cloned.params = {} - Hyrax::CollectionsService.new(cloned) - end - end - end -end - -Hyrax::My::WorksController.prepend(Hyrax::My::WorksControllerDecorator) diff --git a/app/controllers/hyrax/pages_controller.rb b/app/controllers/hyrax/pages_controller.rb deleted file mode 100644 index cdfd8d0a7..000000000 --- a/app/controllers/hyrax/pages_controller.rb +++ /dev/null @@ -1,116 +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 -# - adds @featured_collection_list to show method - -module Hyrax - # Shows the about and help page - class PagesController < ApplicationController - load_and_authorize_resource class: ContentBlock, except: :show - layout :pages_layout - - # 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 - - # OVERRIDE: Adding inject theme views method for theming - around_action :inject_theme_views - - # 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 show - @page = ContentBlock.for(params[:key]) - # 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 here to add featured collection list to show page - @featured_collection_list = FeaturedCollectionList.new - @announcement_text = ContentBlock.for(:announcement) - end - - 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.pages'), hyrax.edit_pages_path - end - - def update - respond_to do |format| - if @page.update(value: update_value_from_params) - redirect_path = "#{hyrax.edit_pages_path}##{params[:content_block].keys.first}" - format.html { redirect_to redirect_path, notice: t(:'hyrax.pages.updated') } - else - format.html { render :edit } - end - end - end - - private - - def permitted_params - params.require(:content_block).permit(:about, - :agreement, - :help, - :terms) - 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 - - def pages_layout - action_name == 'show' ? 'homepage' : 'hyrax/dashboard' - 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 method. This is an override of the view_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/hyrax/pages_controller_decorator.rb b/app/controllers/hyrax/pages_controller_decorator.rb new file mode 100644 index 000000000..3f470a4db --- /dev/null +++ b/app/controllers/hyrax/pages_controller_decorator.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +# OVERRIDE: Hyrax v5.0.0rc2 +# - add inject_theme_views method for theming +# - add homepage presenter for access to feature flippers +# - add access to content blocks in the show method +# - adds @featured_collection_list to show method + +module Hyrax + # Shows the about and help page + module PagesControllerDecorator + 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 + + # OVERRIDE: Hyrax v5.0.0rc2 Add for theming + class_attribute :presenter_class + self.presenter_class = Hyrax::HomepagePresenter + end + + # OVERRIDE: Add for theming + # The search builder for finding recent documents + # Override of Blacklight::RequestBuilders + def search_builder_class + Hyrax::HomepageSearchBuilder + end + + def show + super + + # OVERRIDE: Additional 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 + + 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 method. This is an override of the view_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 + +Hyrax::PagesController.prepend(Hyrax::PagesControllerDecorator) diff --git a/app/controllers/identity_providers_controller.rb b/app/controllers/identity_providers_controller.rb index 28774a0bc..7656e9c6e 100644 --- a/app/controllers/identity_providers_controller.rb +++ b/app/controllers/identity_providers_controller.rb @@ -7,6 +7,7 @@ class IdentityProvidersController < ApplicationController before_action :set_identity_provider, only: %i[edit update destroy] def index + add_breadcrumbs @identity_providers = IdentityProvider.all end @@ -72,27 +73,27 @@ def add_breadcrumbs private - # Use callbacks to share common setup or constraints between actions. - def set_identity_provider - @identity_provider = IdentityProvider.find(params[:id]) - end + # Use callbacks to share common setup or constraints between actions. + def set_identity_provider + @identity_provider = IdentityProvider.find(params[:id]) + end - def ensure_admin! - authorize! :read, :admin_dashboard - end + def ensure_admin! + authorize! :read, :admin_dashboard + end - # Only allow a list of trusted parameters through. - def identity_provider_params - return @identity_provider_params if @identity_provider_params - @identity_provider_params = params.require(:identity_provider).permit( - :name, - :provider, - :options, - :logo_image, - :logo_image_text - ) - @identity_provider_params['options'].presence && - @identity_provider_params['options'] = JSON.parse(@identity_provider_params['options']) - @identity_provider_params - end + # Only allow a list of trusted parameters through. + def identity_provider_params + return @identity_provider_params if @identity_provider_params + @identity_provider_params = params.require(:identity_provider).permit( + :name, + :provider, + :options, + :logo_image, + :logo_image_text + ) + @identity_provider_params['options'].presence && + @identity_provider_params['options'] = JSON.parse(@identity_provider_params['options']) + @identity_provider_params + end end diff --git a/app/controllers/labels_controller.rb b/app/controllers/labels_controller.rb index 7252920bf..df13a1fba 100644 --- a/app/controllers/labels_controller.rb +++ b/app/controllers/labels_controller.rb @@ -23,10 +23,10 @@ def update private - # Never trust parameters from the scary internet, only allow the permitted parameters through. - def site_params - params.require(:site).permit(:application_name, - :institution_name, - :institution_name_full) - end + # Never trust parameters from the scary internet, only allow the permitted parameters through. + def site_params + params.require(:site).permit(:application_name, + :institution_name, + :institution_name_full) + end end diff --git a/app/controllers/proprietor/accounts_controller.rb b/app/controllers/proprietor/accounts_controller.rb index d21986cf1..9f3dd8f86 100644 --- a/app/controllers/proprietor/accounts_controller.rb +++ b/app/controllers/proprietor/accounts_controller.rb @@ -87,41 +87,41 @@ def destroy private - def ensure_admin! - authorize! :read, :admin_dashboard - end + def ensure_admin! + authorize! :read, :admin_dashboard + end - # Never trust parameters from the scary internet, only allow the permitted parameters through. - def edit_account_params - params.require(:account).permit(:name, - :cname, - :title, - :is_public, - :search_only, - *@account.live_settings.keys, - admin_emails: [], - full_account_cross_searches_attributes: [:id, - :_destroy, - :full_account_id, - full_account_attributes: [:id]], - solr_endpoint_attributes: %i[id url], - fcrepo_endpoint_attributes: %i[id url base_path], - data_cite_endpoint_attributes: %i[mode prefix username password]) - end + # Never trust parameters from the scary internet, only allow the permitted parameters through. + def edit_account_params + params.require(:account).permit(:name, + :cname, + :title, + :is_public, + :search_only, + *@account.live_settings.keys, + admin_emails: [], + full_account_cross_searches_attributes: [:id, + :_destroy, + :full_account_id, + full_account_attributes: [:id]], + solr_endpoint_attributes: %i[id url], + fcrepo_endpoint_attributes: %i[id url base_path], + data_cite_endpoint_attributes: %i[mode prefix username password]) + end - def account_params - params.require(:account).permit( - :name, - :search_only, - admin_emails: [], - full_account_cross_searches_attributes: [:id, :_destroy, :full_account_id, full_account_attributes: [:id]] - ) - end + def account_params + params.require(:account).permit( + :name, + :search_only, + admin_emails: [], + full_account_cross_searches_attributes: [:id, :_destroy, :full_account_id, full_account_attributes: [:id]] + ) + end - def deleted_or_new(hash) - hash.detect do |_k, v| - ActiveModel::Type::Boolean.new.cast(v["_destroy"]) == true || v["id"].blank? - end + def deleted_or_new(hash) + hash.detect do |_k, v| + ActiveModel::Type::Boolean.new.cast(v["_destroy"]) == true || v["id"].blank? end + end end end diff --git a/app/controllers/proprietor/users_controller.rb b/app/controllers/proprietor/users_controller.rb index 1aa371c38..bcd44e7a5 100644 --- a/app/controllers/proprietor/users_controller.rb +++ b/app/controllers/proprietor/users_controller.rb @@ -83,44 +83,46 @@ def destroy private - def ensure_admin! - authorize! :read, :admin_dashboard - end + def ensure_admin! + authorize! :read, :admin_dashboard + end - def user_params - # remove blank passwords - params[:user].delete(:password) if params[:user] && params[:user][:password].blank? + # rubocop:disable Metrics/MethodLength + def user_params + # remove blank passwords + params[:user].delete(:password) if params[:user] && params[:user][:password].blank? - params.require(:user).permit(:email, - :password, - :is_superadmin, - :facebook_handle, - :twitter_handle, - :googleplus_handle, - :display_name, - :address, - :department, - :title, - :office, - :chat_id, - :website, - :affiliation, - :telephone, - :avatar, - :group_list, - :linkedin_handle, - :orcid, - :arkivo_token, - :arkivo_subscription, - :zotero_token, - :zotero_userid, - :preferred_locale, - role_ids: []) - end + params.require(:user).permit(:email, + :password, + :is_superadmin, + :facebook_handle, + :twitter_handle, + :googleplus_handle, + :display_name, + :address, + :department, + :title, + :office, + :chat_id, + :website, + :affiliation, + :telephone, + :avatar, + :group_list, + :linkedin_handle, + :orcid, + :arkivo_token, + :arkivo_subscription, + :zotero_token, + :zotero_userid, + :preferred_locale, + role_ids: []) + end + # rubocop:enable Metrics/MethodLength - def find_user - @user ||= ::User.from_url_component(params[:id]) - raise ActiveRecord::RecordNotFound unless @user - end + def find_user + @user ||= ::User.from_url_component(params[:id]) + raise ActiveRecord::RecordNotFound unless @user + end end end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb deleted file mode 100644 index f3c2a64cd..000000000 --- a/app/controllers/roles_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -## -# CRUD actions for assigning exhibit roles to -# existing users -class RolesController < ApplicationController - load_and_authorize_resource :user, parent: false - layout 'hyrax/dashboard' - - before_action do - authorize! :manage, Role - end - - def index - @users = User.all - add_breadcrumb t(:'hyrax.controls.home'), root_path - add_breadcrumb t(:'hyrax.dashboard.breadcrumbs.admin'), hyrax.dashboard_path - add_breadcrumb t(:'hyrax.admin.sidebar.roles_and_permissions'), site_roles_path - end - - def update - if @user.update(user_params) - redirect_to site_roles_path, notice: notice - else - render action: 'index' - end - end - - protected - - def user_params - params.require(:user).permit(site_roles: []) - end -end diff --git a/app/controllers/saved_searches_controller.rb b/app/controllers/saved_searches_controller.rb new file mode 100644 index 000000000..f2618be72 --- /dev/null +++ b/app/controllers/saved_searches_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class SavedSearchesController < ApplicationController + include Blacklight::SavedSearches + + helper BlacklightAdvancedSearch::RenderConstraintsOverride +end diff --git a/app/controllers/search_history_controller.rb b/app/controllers/search_history_controller.rb new file mode 100644 index 000000000..eb6c0983a --- /dev/null +++ b/app/controllers/search_history_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class SearchHistoryController < ApplicationController + include Blacklight::SearchHistory + helper BlacklightAdvancedSearch::RenderConstraintsOverride + helper RangeLimitHelper +end diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb index 166f6390f..5dc8efe6b 100644 --- a/app/controllers/sites_controller.rb +++ b/app/controllers/sites_controller.rb @@ -19,36 +19,36 @@ def update private - def set_site - @site ||= Site.instance - end + def set_site + @site ||= Site.instance + end - def update_params - params.permit(:remove_banner_image, - :remove_favicon, - :remove_logo_image, - :remove_directory_image, - :remove_default_collection_image, - :remove_default_work_image) - end + def update_params + params.permit(:remove_banner_image, + :remove_favicon, + :remove_logo_image, + :remove_directory_image, + :remove_default_collection_image, + :remove_default_work_image) + end - def site_theme_params - params.require(:site).permit(:home_theme, :search_theme, :show_theme) - end + def site_theme_params + params.require(:site).permit(:home_theme, :search_theme, :show_theme) + end - REMOVE_TEXT_MAPS = { - "remove_logo_image" => "logo_image_text", - "remove_banner_image" => "banner_image_text", - "remove_directory_image" => "directory_image_text", - "remove_default_collection_image" => "default_collection_image_text", - "remove_default_work_image" => "default_work_image_text" - }.freeze - - def remove_appearance_text(update_params) - image_text_keys = update_params.keys - image_text_keys.each do |image_text_key| - block = ContentBlock.find_by(name: REMOVE_TEXT_MAPS[image_text_key]) - block.delete if block&.value.present? - end + REMOVE_TEXT_MAPS = { + "remove_logo_image" => "logo_image_text", + "remove_banner_image" => "banner_image_text", + "remove_directory_image" => "directory_image_text", + "remove_default_collection_image" => "default_collection_image_text", + "remove_default_work_image" => "default_work_image_text" + }.freeze + + def remove_appearance_text(update_params) + image_text_keys = update_params.keys + image_text_keys.each do |image_text_key| + block = ContentBlock.find_by(name: REMOVE_TEXT_MAPS[image_text_key]) + block.delete if block&.value.present? end + end end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index f5cff3c0f..0509c6e40 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -30,7 +30,7 @@ def callback alias saml callback def passthru - render status: 404, plain: 'Not found. Authentication passthru.' + render status: :not_found, plain: 'Not found. Authentication passthru.' end # def failure diff --git a/app/forms/hyrax/forms/admin/appearance.rb b/app/forms/hyrax/forms/admin/appearance_decorator.rb similarity index 55% rename from app/forms/hyrax/forms/admin/appearance.rb rename to app/forms/hyrax/forms/admin/appearance_decorator.rb index 7f20affae..96ffb8019 100644 --- a/app/forms/hyrax/forms/admin/appearance.rb +++ b/app/forms/hyrax/forms/admin/appearance_decorator.rb @@ -1,83 +1,143 @@ # frozen_string_literal: true -# OVERRIDE Hyrax 3.4.0 ot add custom theming +# OVERRIDE Hyrax v5.0.0rc2 to add custom theming -# rubocop:disable Metrics/ClassLength +# rubocop:disable Metrics/ModuleLength module Hyrax module Forms module Admin # An object to model and persist the form data for the appearance # customization menu - class Appearance - extend ActiveModel::Naming - delegate :banner_image, :banner_image?, to: :site - delegate :logo_image, :logo_image?, to: :site - delegate :favicon, :favicon?, to: :site - delegate :directory_image, :directory_image?, to: :site - delegate :default_collection_image, :default_collection_image?, to: :site - delegate :default_work_image, :default_work_image?, to: :site - - DEFAULT_FONTS = { - 'body_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;', - 'headline_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;' - }.freeze - - DEFAULT_COLORS = { - 'header_and_footer_background_color' => '#3c3c3c', - 'header_and_footer_text_color' => '#dcdcdc', - 'navbar_background_color' => '#000000', - 'navbar_link_background_hover_color' => '#ffffff', - 'navbar_link_text_color' => '#eeeeee', - 'navbar_link_text_hover_color' => '#eeeeee', - 'link_color' => '#2e74b2', - 'link_hover_color' => '#215480', - 'footer_link_color' => '#ffebcd', - 'footer_link_hover_color' => '#ffffff', - 'primary_button_hover_color' => '#286090', - 'default_button_background_color' => '#ffffff', - 'default_button_border_color' => '#cccccc', - 'default_button_text_color' => '#333333', - # 'active_tabs_background_color' => '#337ab7', - 'facet_panel_background_color' => '#f5f5f5', - 'facet_panel_text_color' => '#333333' - }.freeze - - DEFAULT_VALUES = DEFAULT_FONTS.merge(DEFAULT_COLORS).freeze - - # @param [Hash] attributes the list of parameters from the form - def initialize(attributes = {}) - @attributes = attributes - end - - attr_reader :attributes - private :attributes - - # This allows this object to route to the correct path - def self.model_name - ActiveModel::Name.new(self, Hyrax, "Hyrax::Admin::Appearance") - end - - # Override this method if your form takes more than just the customization_params - def self.permitted_params - customization_params + image_params - end - - def self.image_params - %i[favicon banner_image logo_image directory_image default_collection_image default_work_image] - end + module AppearanceDecorator + extend ActiveSupport::Concern + + # rubocop:disable Metrics/BlockLength + prepended do + delegate :banner_image, :banner_image?, to: :site + delegate :logo_image, :logo_image?, to: :site + delegate :favicon, :favicon?, to: :site + delegate :directory_image, :directory_image?, to: :site + delegate :default_collection_image, :default_collection_image?, to: :site + delegate :default_work_image, :default_work_image?, to: :site + + ## + # @!group Class Attributes + # + # @!attribute default_fonts + # @return [Hash] there should be at least the key "body_font" and + # "headline_font" + class_attribute :default_fonts, default: { + 'body_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;', + 'headline_font' => 'Helvetica Neue, Helvetica, Arial, sans-serif;' + } + + ## + # @!attribute default_colors + # @return [Hash] + class_attribute :default_colors, default: { + 'header_and_footer_background_color' => '#3c3c3c', + 'header_and_footer_text_color' => '#dcdcdc', + 'navbar_background_color' => '#000000', + 'navbar_link_background_hover_color' => '#ffffff', + 'navbar_link_text_color' => '#eeeeee', + 'navbar_link_text_hover_color' => '#eeeeee', + 'link_color' => '#2e74b2', + 'link_hover_color' => '#215480', + 'footer_link_color' => '#ffebcd', + 'footer_link_hover_color' => '#ffffff', + 'primary_button_hover_color' => '#286090', + 'default_button_background_color' => '#ffffff', + 'default_button_border_color' => '#cccccc', + 'default_button_text_color' => '#333333', + # 'active_tabs_background_color' => '#337ab7', + 'facet_panel_background_color' => '#f5f5f5', + 'facet_panel_text_color' => '#333333' + } + # @!endgroup Class Attributes + end + + class_methods do + # Override this method if your form takes more than just the customization_params + def permitted_params + customization_params + image_params + end - def site - @site ||= Site.instance - end + def image_params + %i[favicon banner_image logo_image directory_image default_collection_image default_work_image] + end - # Required to back a form - def to_key - [] + # @return [Array] a list of fields that are related to the banner + def banner_fields + %i[ + banner_image banner_label + ] + end + + def favicon_fields + [:favicon] + end + + # @return [Array] a list of fields that are related to the logo + def logo_fields + %i[ + logo_image logo_label + ] + end + + # @return [Array] a list of fields that are related to the directory + def directory_fields + %i[ + directory_image directory_image_label + ] + end + + # @return [Array] a list of fields that are related to default works & collections + def default_image_fields + %i[ + default_collection_image + default_work_image + default_collection_label + default_work_label + ] + end + + # A list of parameters that are related to customizations + # rubocop:disable Metrics/MethodLength + def customization_params + %i[ + body_font + headline_font + header_and_footer_background_color + header_and_footer_text_color + link_color + link_hover_color + footer_link_color + footer_link_hover_color + primary_button_hover_color + default_button_background_color + default_button_border_color + default_button_text_color + active_tabs_background_color + facet_panel_background_color + facet_panel_text_color + navbar_background_color + navbar_link_background_hover_color + navbar_link_text_color + navbar_link_text_hover_color + custom_css_block + logo_image_text + banner_image_text + directory_image_text + default_collection_image_text + default_work_image_text + ] + end + # rubocop:enable Metrics/MethodLength end + # rubocop:enable Metrics/BlockLength - # Required to back a form (for route determination) - def persisted? - true + def site + @site ||= Site.instance end # The alt text for the logo image @@ -190,35 +250,22 @@ def primary_button_hover_background_color darken_color(primary_button_hover_color, 0.1) end - # The mouse over color for the border of "primary" buttons - def primary_button_hover_border_color - darken_color(primary_button_border_color, 0.12) - end - # The color for the background of active "primary" buttons def primary_button_active_background_color darken_color(primary_button_hover_color, 0.1) end - # The color for the border of active "primary" buttons - def primary_button_active_border_color - darken_color(primary_button_border_color, 0.12) - end - # The color for the background of focused "primary" buttons def primary_button_focus_background_color darken_color(primary_button_hover_color, 0.1) end - # The color for the border of focused "primary" buttons - def primary_button_focus_border_color - darken_color(primary_button_border_color, 0.25) - end - # The custom css module def custom_css_block # we want to be able to read the css + # rubocop:disable Rails/OutputSafety block_for('custom_css_block', '/* custom stylesheet */').html_safe + # rubocop:enable Rails/OutputSafety end # DEFAULT BUTTON COLORS @@ -315,41 +362,6 @@ def default_image_attributes attributes.slice(*self.class.default_image_fields) end - # @return [Array] a list of fields that are related to the banner - def self.banner_fields - %i[ - banner_image banner_label - ] - end - - def self.favicon_fields - [:favicon] - end - - # @return [Array] a list of fields that are related to the logo - def self.logo_fields - %i[ - logo_image logo_label - ] - end - - # @return [Array] a list of fields that are related to the directory - def self.directory_fields - %i[ - directory_image directory_image_label - ] - end - - # @return [Array] a list of fields that are related to default works & collections - def self.default_image_fields - %i[ - default_collection_image - default_work_image - default_collection_label - default_work_label - ] - end - # Persist the form values def update! self.class.customization_params.each do |field| @@ -362,37 +374,6 @@ def update! .merge(default_image_attributes)) end - # A list of parameters that are related to customizations - def self.customization_params - %i[ - body_font - headline_font - header_and_footer_background_color - header_and_footer_text_color - link_color - link_hover_color - footer_link_color - footer_link_hover_color - primary_button_hover_color - default_button_background_color - default_button_border_color - default_button_text_color - active_tabs_background_color - facet_panel_background_color - facet_panel_text_color - navbar_background_color - navbar_link_background_hover_color - navbar_link_text_color - navbar_link_text_hover_color - custom_css_block - logo_image_text - banner_image_text - directory_image_text - default_collection_image_text - default_work_image_text - ] - end - def font_import_body_url body = body_font.split('|').first.to_s.tr(" ", "+") # we need to be able to read the url to import fonts @@ -414,41 +395,49 @@ def font_headline_family private - def darken_color(hex_color, adjustment = 0.2) - amount = 1.0 - adjustment - hex_color = hex_color.delete('#') - rgb = hex_color.scan(/../).map { |color| (color.to_i(16) * amount).round } - rgb[0] = (rgb[0].to_i * amount).round - rgb[1] = (rgb[1].to_i * amount).round - rgb[2] = (rgb[2].to_i * amount).round - format("#%02x%02x%02x", *rgb) - end + def darken_color(hex_color, adjustment = 0.2) + amount = 1.0 - adjustment + hex_color = hex_color.delete('#') + rgb = hex_color.scan(/../).map { |color| (color.to_i(16) * amount).round } + rgb[0] = (rgb[0].to_i * amount).round + rgb[1] = (rgb[1].to_i * amount).round + rgb[2] = (rgb[2].to_i * amount).round + format("#%02x%02x%02x", *rgb) + end - def convert_to_rgba(hex_color, alpha = 0.5) - hex_color = hex_color.delete('#') - rgb = hex_color.scan(/../).map(&:hex) - "rgba(#{rgb[0]}, #{rgb[1]}, #{rgb[2]}, #{alpha})" - end + def convert_to_rgba(hex_color, alpha = 0.5) + hex_color = hex_color.delete('#') + rgb = hex_color.scan(/../).map(&:hex) + "rgba(#{rgb[0]}, #{rgb[1]}, #{rgb[2]}, #{alpha})" + end - def block_for(name, dynamic_default = nil) - ContentBlock.block_for(name: name, fallback_value: DEFAULT_VALUES[name] || dynamic_default) - end + def default_values + @default_values ||= default_fonts.merge(default_colors) + end - # Persist a key/value tuple as a ContentBlock - # @param [Symbol] name the identifier for the ContentBlock - # @param [String] value the value to set - def update_block(name, value) - ContentBlock.update_block(name: name, value: value) - end + def block_for(name, dynamic_default = nil) + ContentBlock.block_for(name:, fallback_value: default_values[name] || dynamic_default) + end - def format_font_names(font_style) - # the fonts come with `Font Name:font-weight` - this removes the weight - parts = font_style.split(':') - # Google fonts use `+` in place of spaces. This fixes it for CSS. - parts[0].tr('+', ' ').html_safe - end + # Persist a key/value tuple as a ContentBlock + # @param [Symbol] name the identifier for the ContentBlock + # @param [String] value the value to set + def update_block(name, value) + ContentBlock.update_block(name:, value:) + end + + def format_font_names(font_style) + # the fonts come with `Font Name:font-weight` - this removes the weight + parts = font_style.split(':') + # Google fonts use `+` in place of spaces. This fixes it for CSS. + # rubocop:disable Rails/OutputSafety + parts[0].tr('+', ' ').html_safe + # rubocop:enable Rails/OutputSafety + end end end end end -# rubocop:enable Metrics/ClassLength +# rubocop:enable Metrics/ModuleLength + +Hyrax::Forms::Admin::Appearance.prepend(Hyrax::Forms::Admin::AppearanceDecorator) diff --git a/app/forms/hyrax/forms/permission_template_form_decorator.rb b/app/forms/hyrax/forms/permission_template_form_decorator.rb index c09e514f2..7eda3fe0b 100644 --- a/app/forms/hyrax/forms/permission_template_form_decorator.rb +++ b/app/forms/hyrax/forms/permission_template_form_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hyrax 3.4.1 to fix Hyrax::Groups args +# OVERRIDE Hyrax v5.0.0rc2 to fix Hyrax::Groups args module Hyrax module Forms module PermissionTemplateFormDecorator diff --git a/app/forms/hyrax/forms/workflow_responsibility_form_decorator.rb b/app/forms/hyrax/forms/workflow_responsibility_form_decorator.rb new file mode 100644 index 000000000..87119cdba --- /dev/null +++ b/app/forms/hyrax/forms/workflow_responsibility_form_decorator.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v5.0.0rc2 Expand to allow adding groups to workflow roles + +module Hyrax + module Forms + module WorkflowResponsibilityFormDecorator + ## + # @note We introduced this little crease in the code to allow for conditional switching; and + # thus avoid copying a very large controller + # (e.g. Hyrax::Admin::WorkflowRolesController) + # @see Hyrax::Forms::WorkflowResponsibilityGroupForm + module ClassMethods + ## + # Determine which form it is, user or group. By default, it will be a user + # (e.g. {Hyrax::Forms::WorkflowResponsibilityForm}); however when you provide a :group_id it + # will be a group form (e.g. {Hyrax::Forms::WorkflowResponsibilityGroupForm}. + def new(params = {}) + if params[:group_id].present? + Forms::WorkflowResponsibilityGroupForm.new(params) + else + super + end + end + end + end + end +end + +Hyrax::Forms::WorkflowResponsibilityForm.singleton_class + .send(:prepend, Hyrax::Forms::WorkflowResponsibilityFormDecorator::ClassMethods) diff --git a/app/forms/hyrax/forms/workflow_responsibility_group_form.rb b/app/forms/hyrax/forms/workflow_responsibility_group_form.rb index 71f4323fb..7cb6d0715 100644 --- a/app/forms/hyrax/forms/workflow_responsibility_group_form.rb +++ b/app/forms/hyrax/forms/workflow_responsibility_group_form.rb @@ -10,6 +10,11 @@ def initialize(params = {}) model_instance.agent = group.to_sipity_agent end + ## + # This method is necessary for the HTML form fields to have the correct name (e.g. ``). + # + # @see ActiveModel::Naming def model_instance @model ||= Sipity::WorkflowResponsibility.new end diff --git a/app/helpers/admin_stats_helper.rb b/app/helpers/admin_stats_helper.rb index e1558e502..bcd96b677 100644 --- a/app/helpers/admin_stats_helper.rb +++ b/app/helpers/admin_stats_helper.rb @@ -5,7 +5,7 @@ def graph_tag(id, data, options) content_tag :div, class: 'graph-container', data: { graph_data: data.to_json, graph_options: options } do - content_tag :div, nil, class: 'graph', id: id + content_tag :div, nil, class: 'graph', id: end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e27eee4ae..0e8cba8e7 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,9 +5,10 @@ module ApplicationHelper include Hyrax::OverrideHelperBehavior include GroupNavigationHelper include SharedSearchHelper + include HykuKnapsack::ApplicationHelper def hint_for(term:, record_class: nil) - hint = locale_for(type: 'hints', term: term, record_class: record_class) + hint = locale_for(type: 'hints', term:, record_class:) return hint unless missing_translation(hint) end @@ -24,7 +25,8 @@ def locale_for(type:, term:, record_class:) locale end - def missing_translation(value) - value.include?('translation missing') + def missing_translation(value, _options = {}) + return true if value.try(:false?) + false end end diff --git a/app/helpers/blacklight/blacklight_helper_behavior.rb b/app/helpers/blacklight/blacklight_helper_behavior.rb deleted file mode 100644 index b1c0778e4..000000000 --- a/app/helpers/blacklight/blacklight_helper_behavior.rb +++ /dev/null @@ -1,423 +0,0 @@ -# frozen_string_literal: true - -# Override Blacklight v6.23.0 to add preferred view from search theme - Hyku Theming -# Methods added to this helper will be available to all templates in the hosting application -module Blacklight - module BlacklightHelperBehavior - include BlacklightUrlHelper - include BlacklightConfigurationHelper - include HashAsHiddenFieldsHelper - include RenderConstraintsHelper - include RenderPartialsHelper - include FacetsHelper - extend Deprecation - self.deprecation_horizon = 'Blacklight version 7.0.0' - - ## - # Get the name of this application, from either: - # - the Rails configuration - # - an i18n string (key: blacklight.application_name; preferred) - # - # @return [String] the application name - def application_name - if Rails.application.config.respond_to? :application_name - Deprecation.warn( - self, "BlacklightHelper#application_name will no longer delegate to config.application_name - in version 7.0. Set the i18n for blacklight.application_name instead" - ) - return Rails.application.config.application_name - end - - t('blacklight.application_name') - end - - ## - # Get the page's HTML title - # - # @return [String] - def render_page_title - (content_for(:page_title) if content_for?(:page_title)) || @page_title || application_name - end - - ## - # Create links from a documents dynamically - # provided export formats. - # - # Returns empty string if no links available. - # - # @param [SolrDocument] document - # @param [Hash] options - # @option options [Boolean] :unique ensures only one link is output for every - # content type, e.g. as required by atom - # @option options [Array] :exclude array of format shortnames to not include in the output - def render_link_rel_alternates(document = @document, options = {}) - return if document.nil? - presenter(document).link_rel_alternates(options) - end - - ## - # Render OpenSearch headers for this search - # @return [String] - def render_opensearch_response_metadata - render partial: 'catalog/opensearch_response_metadata' - end - - ## - # Render classes for the element - # @return [String] - def render_body_class - extra_body_classes.join " " - end - - ## - # List of classes to be applied to the element - # @see render_body_class - # @return [Array] - def extra_body_classes - @extra_body_classes ||= [ - 'blacklight-' + controller.controller_name, - 'blacklight-' + [controller.controller_name, controller.action_name].join('-') - ] - end - - ## - # Render the search navbar - # @return [String] - def render_search_bar - render partial: 'catalog/search_form' - end - - ## - # Determine whether to render a given field in the index view. - # - # @param [SolrDocument] document - # @param [Blacklight::Configuration::Field] field_config - # @return [Boolean] - def should_render_index_field?(document, field_config) - should_render_field?(field_config, document) && document_has_value?(document, field_config) - end - - ## - # Determine whether to render a given field in the show view - # - # @param [SolrDocument] document - # @param [Blacklight::Configuration::Field] field_config - # @return [Boolean] - def should_render_show_field?(document, field_config) - should_render_field?(field_config, document) && document_has_value?(document, field_config) - end - - ## - # Check if a document has (or, might have, in the case of accessor methods) a value for - # the given solr field - # @param [SolrDocument] document - # @param [Blacklight::Configuration::Field] field_config - # @return [Boolean] - def document_has_value?(document, field_config) - document.has?(field_config.field) || - (document.has_highlight_field? field_config.field if field_config.highlight) || - field_config.accessor - end - - ## - # Determine whether to display spellcheck suggestions - # - # @param [Blacklight::Solr::Response] response - # @return [Boolean] - def should_show_spellcheck_suggestions?(response) - response.total <= spell_check_max && - !response.spelling.nil? && - response.spelling.words.any? - end - - ## - # Render the index field label for a document - # - # @overload render_index_field_label(options) - # Use the default, document-agnostic configuration - # @param [Hash] opts - # @option opts [String] :field - # @overload render_index_field_label(document, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [Hash] opts - # @option opts [String] :field - def render_index_field_label(*args) - options = args.extract_options! - document = args.first - - field = options[:field] - html_escape t( - :"blacklight.search.index.#{document_index_view_type}.label", - default: :'blacklight.search.index.label', - label: index_field_label(document, field) - ) - end - - ## - # Render the index field label for a document - # - # @overload render_index_field_value(options) - # Use the default, document-agnostic configuration - # @param [Hash] opts - # @option opts [String] :field - # @option opts [String] :value - # @option opts [String] :document - # @overload render_index_field_value(document, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [Hash] opts - # @option opts [String] :field - # @option opts [String] :value - # @overload render_index_field_value(document, field, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [String] field - # @param [Hash] opts - # @option opts [String] :value - # @deprecated use IndexPresenter#field_value - def render_index_field_value(*args) - render_field_value(*args) - end - deprecation_deprecate render_index_field_value: 'replaced by IndexPresenter#field_value' - - # @deprecated use IndexPresenter#field_value - def render_field_value(*args) - options = args.extract_options! - document = args.shift || options[:document] - - field = args.shift || options[:field] - presenter(document).field_value field, options.except(:document, :field) - end - deprecation_deprecate render_field_value: 'replaced by IndexPresenter#field_value' - - ## - # Render the show field label for a document - # - # @overload render_document_show_field_label(options) - # Use the default, document-agnostic configuration - # @param [Hash] opts - # @option opts [String] :field - # @overload render_document_show_field_label(document, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [Hash] opts - # @option opts [String] :field - def render_document_show_field_label(*args) - options = args.extract_options! - document = args.first - - field = options[:field] - - t(:'blacklight.search.show.label', label: document_show_field_label(document, field)) - end - - ## - # Render the index field label for a document - # - # @overload render_document_show_field_value(options) - # Use the default, document-agnostic configuration - # @param [Hash] opts - # @option opts [String] :field - # @option opts [String] :value - # @option opts [String] :document - # @overload render_document_show_field_value(document, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [Hash] opts - # @option opts [String] :field - # @option opts [String] :value - # @overload render_document_show_field_value(document, field, options) - # Allow an extention point where information in the document - # may drive the value of the field - # @param [SolrDocument] doc - # @param [String] field - # @param [Hash] opts - # @option opts [String] :value - # @deprecated use ShowPresenter#field_value - def render_document_show_field_value(*args) - render_field_value(*args) - end - deprecation_deprecate render_document_show_field_value: 'replaced by ShowPresenter#field_value' - - ## - # Get the value of the document's "title" field, or a placeholder - # value (if empty) - # - # @param [SolrDocument] document - # @return [String] - def document_heading(document = nil) - document ||= @document - presenter(document).heading - end - - ## - # Get the document's "title" to display in the element. - # (by default, use the #document_heading) - # - # @see #document_heading - # @param [SolrDocument] document - # @return [String] - def document_show_html_title(document = nil) - document ||= @document - - presenter(document).html_title - end - - ## - # Render the document "heading" (title) in a content tag - # @overload render_document_heading(document, options) - # @param [SolrDocument] document - # @param [Hash] options - # @option options [Symbol] :tag - # @overload render_document_heading(options) - # @param [Hash] options - # @option options [Symbol] :tag - def render_document_heading(*args) - options = args.extract_options! - document = args.first - tag = options.fetch(:tag, :h4) - document ||= @document - - content_tag(tag, presenter(document).heading, itemprop: "name") - end - - ## - # Get the value for a document's field, and prepare to render it. - # - highlight_field - # - accessor - # - solr field - # - # Rendering: - # - helper_method - # - link_to_search - # @param [SolrDocument] document - # @param [String] _field name - # @param [Blacklight::Configuration::Field] field_config solr field configuration - # @param [Hash] options additional options to pass to the rendering helpers - def get_field_values(document, _field, field_config, options = {}) - presenter(document).field_values field_config, options - end - deprecation_deprecate :get_field_values - - ## - # Get the current "view type" (and ensure it is a valid type) - # - # @param [Hash] query_params the query parameters to check - # @return [Symbol] - def document_index_view_type(query_params = params) - view_param = query_params[:view] - # Override Blacklight v6.23.0 to add preferred view from search theme - Hyku Theming - view_param ||= search_results_theme.split('_').first - view_param ||= session[:preferred_view] - if view_param && document_index_views.keys.include?(view_param.to_sym) - view_param.to_sym - else - default_document_index_view_type - end - end - - ## - # Render a partial of an arbitrary format inside a - # template of a different format. (e.g. render an HTML - # partial from an XML template) - # code taken from: - # http://stackoverflow.com/questions/339130/how-do-i-render-a-partial-of-a-different-format-in-rails (zgchurch) - # - # @param [String] format suffix - # @yield - def with_format(format, _block) - old_formats = formats - self.formats = [format] - yield - self.formats = old_formats - nil - end - - ## - # Should we render a grouped response (because the response - # contains a grouped response instead of the normal response) - def render_grouped_response?(response = @response) - response.grouped? - end - - ## - # Returns a document presenter for the given document - # TODO: Move this to the controller. It can just pass a presenter or set of presenters. - def presenter(document) - case action_name - when 'show', 'citation' - show_presenter(document) - when 'index' - index_presenter(document) - else - Deprecation.warn( - Blacklight::BlacklightHelperBehavior, "Unable to determine presenter type for - #{action_name} on #{controller_name}, falling back on deprecated Blacklight::DocumentPresenter" - ) - presenter_class.new(document, self) - end - end - - def show_presenter(document) - show_presenter_class(document).new(document, self) - end - - def index_presenter(document) - index_presenter_class(document).new(document, self) - end - - def presenter_class - blacklight_config.document_presenter_class - end - deprecation_deprecate presenter_class: "replaced by show_presenter_class and index_presenter_class" - - ## - # Override this method if you want to use a different presenter class - def show_presenter_class(_document) - blacklight_config.show.document_presenter_class - end - - def index_presenter_class(_document) - blacklight_config.index.document_presenter_class - end - - ## - # Open Search discovery tag for HTML <head> links - def opensearch_description_tag(title, href) - tag :link, href: href, title: title, type: "application/opensearchdescription+xml", rel: "search" - end - - # OVERIDE: Blacklight::UrlHelperBehavior: - # override link_to_document to substitute method generate_work_url - # to fix URLs for gallery view groupings in shared tenants - # link_to_document(doc, 'VIEW', :counter => 3) - def link_to_document(doc, field_or_opts = nil, opts = { counter: nil }) - if field_or_opts.is_a? Hash - opts = field_or_opts - else - field = field_or_opts - end - - field ||= document_show_link_field(doc) - label = index_presenter(doc).label field, opts - # pull solr_document from input if we don't already have a solr_document - document = doc&.try(:solr_document) || doc - link_to label, generate_work_url(document, request), document_link_params(document, opts) - end - - # OVERIDE: Blacklight::UrlHelperBehavior: - # disable link jacking for tracking - # see https://playbook-staging.notch8.com/en/samvera/hyku/troubleshooting/multi-tenancy-and-full-urls - # If we need to preserve the link jacking for tracking, then we need to also amend - # method `session_tracking_params`so that instead of a path we have a URL - def document_link_params(_doc, opts) - opts.except(:label, :counter) - end - end -end diff --git a/app/helpers/google_tag_manager_helper.rb b/app/helpers/google_tag_manager_helper.rb index 6a9f6f70c..87518a045 100644 --- a/app/helpers/google_tag_manager_helper.rb +++ b/app/helpers/google_tag_manager_helper.rb @@ -5,7 +5,7 @@ def render_gtm_head(_host) return '' if current_account.gtm_id.blank? # rubocop:disable Rails/OutputSafety - <<-HTML.strip_heredoc.html_safe + <<~HTML.html_safe <!-- Google Tag Manager --> <script> (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': @@ -23,7 +23,7 @@ def render_gtm_body(_host) # render 'layouts/google/gtm_body' return '' if current_account.gtm_id.blank? # rubocop:disable Rails/OutputSafety - <<-HTML.strip_heredoc.html_safe + <<~HTML.html_safe <!-- Google Tag Manager (noscript) --> <noscript><iframe src='https://www.googletagmanager.com/ns.html?id="#{current_account.gtm_id}"' diff --git a/app/helpers/group_navigation_helper.rb b/app/helpers/group_navigation_helper.rb index 2bc90c72e..e29868d8a 100644 --- a/app/helpers/group_navigation_helper.rb +++ b/app/helpers/group_navigation_helper.rb @@ -2,6 +2,6 @@ module GroupNavigationHelper def navigation_presenter - @navigation_presenter ||= Hyku::Admin::Group::NavigationPresenter.new(params: params) + @navigation_presenter ||= Hyku::Admin::Group::NavigationPresenter.new(params:) end end diff --git a/app/helpers/hyku/blacklight_helper_behavior.rb b/app/helpers/hyku/blacklight_helper_behavior.rb new file mode 100644 index 000000000..91be4cd8a --- /dev/null +++ b/app/helpers/hyku/blacklight_helper_behavior.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +# Override Blacklight v7.35.0 to add preferred view from search theme - Hyku Theming +# Methods added to this helper will be available to all templates in the hosting application +module Hyku + module BlacklightHelperBehavior + ## + # Get the current "view type" (and ensure it is a valid type) + # + # @param [Hash] query_params the query parameters to check + # @return [Symbol] + def document_index_view_type(query_params = params) + view_param = query_params[:view] + view_param ||= search_results_theme.split('_').first + view_param ||= session[:preferred_view] + if view_param && document_index_views.key?(view_param.to_sym) + view_param.to_sym + else + default_document_index_view_type + end + end + + # OVERRIDE: Blacklight::UrlHelperBehavior: + # override link_to_document to substitute method generate_work_url + # to fix URLs for gallery view groupings in shared tenants + # link_to_document(doc, 'VIEW', :counter => 3) + # rubocop:disable Metrics/MethodLength + def link_to_document(doc, field_or_opts = nil, opts = { counter: nil }) + label = case field_or_opts + when NilClass + document_presenter(doc).heading + when Hash + opts = field_or_opts + document_presenter(doc).heading + when Proc, Symbol + Deprecation.warn(self, "passing a #{field_or_opts.class} to link_to_document is deprecated and will be removed in Blacklight 8") + Deprecation.silence(Blacklight::IndexPresenter) do + index_presenter(doc).label field_or_opts, opts + end + else # String + field_or_opts + end + + # pull solr_document from input if we don't already have a solr_document + document = doc&.try(:solr_document) || doc + Deprecation.silence(Blacklight::UrlHelperBehavior) do + link_to label, generate_work_url(document, request), document_link_params(document, opts) + end + end + # rubocop:enable Metrics/MethodLength + + # OVERRIDE: Blacklight::UrlHelperBehavior: + # disable link jacking for tracking + # see https://playbook-staging.notch8.com/en/samvera/hyku/troubleshooting/multi-tenancy-and-full-urls + # If we need to preserve the link jacking for tracking, then we need to also amend + # method `session_tracking_params`so that instead of a path we have a URL + # @private + def document_link_params(_doc, opts) + opts.except(:label, :counter) + end + private :document_link_params + end +end diff --git a/app/helpers/hyrax_helper.rb b/app/helpers/hyrax_helper.rb index 921498837..fd1caaecb 100644 --- a/app/helpers/hyrax_helper.rb +++ b/app/helpers/hyrax_helper.rb @@ -4,6 +4,7 @@ module HyraxHelper include ::BlacklightHelper include Hyrax::BlacklightOverride include Hyrax::HyraxHelperBehavior + include Hyku::BlacklightHelperBehavior def application_name Site.application_name || super @@ -26,7 +27,7 @@ def logo_image end def block_for(name:) - ContentBlock.block_for(name: name, fallback_value: false) + ContentBlock.block_for(name:, fallback_value: false) end def directory_image diff --git a/app/helpers/shared_search_helper.rb b/app/helpers/shared_search_helper.rb index ef419f6cb..0bbae1b18 100644 --- a/app/helpers/shared_search_helper.rb +++ b/app/helpers/shared_search_helper.rb @@ -17,20 +17,20 @@ def generate_work_url(model, request) id = model["id"] end request_params = %i[protocol host port].map { |method| ["request_#{method}".to_sym, request.send(method)] }.to_h - get_url(id: id, request: request_params, account_cname: account_cname, has_model: has_model) + get_url(id:, request: request_params, account_cname:, has_model:) end private - def get_url(id:, request:, account_cname:, has_model:) - new_url = "#{request[:request_protocol]}#{account_cname || request[:request_host]}" - new_url += ":#{request[:request_port]}" if Rails.env.development? || Rails.env.test? - new_url += case has_model - when "collections" - "/#{has_model}/#{id}" - else - "/concern/#{has_model}/#{id}" - end - new_url - end + def get_url(id:, request:, account_cname:, has_model:) + new_url = "#{request[:request_protocol]}#{account_cname || request[:request_host]}" + new_url += ":#{request[:request_port]}" if Rails.env.development? || Rails.env.test? + new_url += case has_model + when "collections" + "/#{has_model}/#{id}" + else + "/concern/#{has_model}/#{id}" + end + new_url + end end diff --git a/app/jobs/cleanup_account_job.rb b/app/jobs/cleanup_account_job.rb index 504436f0b..6dcc500e0 100644 --- a/app/jobs/cleanup_account_job.rb +++ b/app/jobs/cleanup_account_job.rb @@ -13,21 +13,21 @@ def perform(account) private - def cleanup_fedora(account) - account.fcrepo_endpoint.remove! - end + def cleanup_fedora(account) + account.fcrepo_endpoint.remove! + end - def cleanup_redis(account) - account.redis_endpoint.remove! - end + def cleanup_redis(account) + account.redis_endpoint.remove! + end - def cleanup_solr(account) - account.solr_endpoint.remove! - end + def cleanup_solr(account) + account.solr_endpoint.remove! + end - def cleanup_database(account) - Apartment::Tenant.drop(account.tenant) - rescue StandardError - nil # ignore if account.tenant missing - end + def cleanup_database(account) + Apartment::Tenant.drop(account.tenant) + rescue StandardError + nil # ignore if account.tenant missing + end end diff --git a/app/jobs/create_default_admin_set_job.rb b/app/jobs/create_default_admin_set_job.rb index 592b32f8e..1f8ee9437 100644 --- a/app/jobs/create_default_admin_set_job.rb +++ b/app/jobs/create_default_admin_set_job.rb @@ -2,6 +2,6 @@ class CreateDefaultAdminSetJob < ApplicationJob def perform(_account) - AdminSet.find_or_create_default_admin_set_id + Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id end end diff --git a/app/jobs/create_solr_collection_job.rb b/app/jobs/create_solr_collection_job.rb index 6d56486eb..e818f8fae 100644 --- a/app/jobs/create_solr_collection_job.rb +++ b/app/jobs/create_solr_collection_job.rb @@ -22,10 +22,10 @@ def without_account(name, tenant_list = '') return if collection_exists?(name) if tenant_list.present? client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATEALIAS', - name: name, collections: tenant_list) + name:, collections: tenant_list) else client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATE', - name: name) + name:) end end @@ -50,84 +50,84 @@ def to_h private - def transform_entry(k, v) - case v - when Hash - v.map do |k1, v1| - ["#{transform_key(k)}.#{transform_key(k1)}", v1] - end - else - [transform_key(k), v] + def transform_entry(k, v) + case v + when Hash + v.map do |k1, v1| + ["#{transform_key(k)}.#{transform_key(k1)}", v1] end + else + [transform_key(k), v] end + end - def transform_key(k) - k.to_s.camelize(:lower) - end + def transform_key(k) + k.to_s.camelize(:lower) + end end private - def client - Blacklight.default_index.connection - end + def client + Blacklight.default_index.connection + end - def collection_options - CollectionOptions.new(account ? account.solr_collection_options : Account.solr_collection_options).to_h - end + def collection_options + CollectionOptions.new(account ? account.solr_collection_options : Account.solr_collection_options).to_h + end - def collection_exists?(name) - response = client.get '/solr/admin/collections', params: { action: 'LIST' } - collections = response['collections'] + def collection_exists?(name) + response = client.get '/solr/admin/collections', params: { action: 'LIST' } + collections = response['collections'] - collections.include? name - end + collections.include? name + end - def collection_url(name) - uri = URI(solr_url) + name + def collection_url(name) + uri = URI(solr_url) + name - uri.to_s - end + uri.to_s + end - def solr_url - @solr_url ||= ENV['SOLR_URL'] || solr_url_parts - @solr_url = @solr_url.ends_with?('/') ? @solr_url : "#{@solr_url}/" - end + def solr_url + @solr_url ||= ENV['SOLR_URL'] || solr_url_parts + @solr_url = @solr_url.ends_with?('/') ? @solr_url : "#{@solr_url}/" + end - def solr_url_parts - "http://#{ENV.fetch('SOLR_ADMIN_USER', 'admin')}:#{ENV.fetch('SOLR_ADMIN_PASSWORD', 'admin')}" \ - "@#{ENV.fetch('SOLR_HOST', 'solr')}:#{ENV.fetch('SOLR_PORT', '8983')}/solr/" - end + def solr_url_parts + "http://#{ENV.fetch('SOLR_ADMIN_USER', 'admin')}:#{ENV.fetch('SOLR_ADMIN_PASSWORD', 'admin')}" \ + "@#{ENV.fetch('SOLR_HOST', 'solr')}:#{ENV.fetch('SOLR_PORT', '8983')}/solr/" + end - def add_solr_endpoint_to_account(account, name) - account.create_solr_endpoint(url: collection_url(name), collection: name) - end + def add_solr_endpoint_to_account(account, name) + account.create_solr_endpoint(url: collection_url(name), collection: name) + end - def perform_for_normal_tenant(account, name) - unless collection_exists? name - client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATE', - name: name) - end - add_solr_endpoint_to_account(account, name) + def perform_for_normal_tenant(account, name) + unless collection_exists? name + client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATE', + name:) end + add_solr_endpoint_to_account(account, name) + end - def perform_for_cross_search_tenant(account, name) - return if account.full_accounts.blank? - if account.saved_changes&.[]('created_at').present? || account.solr_endpoint.is_a?(NilSolrEndpoint) - create_shared_search_collection(account.full_accounts.map(&:tenant).uniq, name) - account.create_solr_endpoint(url: collection_url(name), collection: name) - account.save - else - solr_options = account.solr_endpoint.connection_options.dup - RemoveSolrCollectionJob.perform_now(name, solr_options, 'cross_search_tenant') - create_shared_search_collection(account.full_accounts.map(&:tenant).uniq, name) - account.solr_endpoint.update(url: collection_url(name), collection: name) - end + def perform_for_cross_search_tenant(account, name) + return if account.full_accounts.blank? + if account.saved_changes&.[]('created_at').present? || account.solr_endpoint.is_a?(NilSolrEndpoint) + create_shared_search_collection(account.full_accounts.map(&:tenant).uniq, name) + account.create_solr_endpoint(url: collection_url(name), collection: name) + account.save + else + solr_options = account.solr_endpoint.connection_options.dup + RemoveSolrCollectionJob.perform_now(name, solr_options, 'cross_search_tenant') + create_shared_search_collection(account.full_accounts.map(&:tenant).uniq, name) + account.solr_endpoint.update(url: collection_url(name), collection: name) end + end - def create_shared_search_collection(tenant_list, name) - return true if collection_exists?(name) - client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATEALIAS', - name: name, collections: tenant_list) - end + def create_shared_search_collection(tenant_list, name) + return true if collection_exists?(name) + client.get '/solr/admin/collections', params: collection_options.merge(action: 'CREATEALIAS', + name:, collections: tenant_list) + end end diff --git a/app/jobs/delete_old_guests_job.rb b/app/jobs/delete_old_guests_job.rb index 5ca5e0a40..51eafba83 100644 --- a/app/jobs/delete_old_guests_job.rb +++ b/app/jobs/delete_old_guests_job.rb @@ -7,12 +7,12 @@ class DeleteOldGuestsJob < ApplicationJob end def perform - User.unscope(:where).where("guest = ? and updated_at < ?", true, Time.current - 7.days).destroy_all + User.unscope(:where).where("guest = ? and updated_at < ?", true, 7.days.ago).destroy_all end private - def reenqueue - DeleteOldGuestsJob.set(wait_until: Date.tomorrow.midnight).perform_later - end + def reenqueue + DeleteOldGuestsJob.set(wait_until: Date.tomorrow.midnight).perform_later + end end diff --git a/app/jobs/embargo_auto_expiry_job.rb b/app/jobs/embargo_auto_expiry_job.rb index 1b7106eb4..7fe83c7d1 100644 --- a/app/jobs/embargo_auto_expiry_job.rb +++ b/app/jobs/embargo_auto_expiry_job.rb @@ -15,7 +15,7 @@ def perform(account) private - def reenqueue(account) - EmbargoAutoExpiryJob.set(wait_until: Date.tomorrow.midnight).perform_later(account) - end + def reenqueue(account) + EmbargoAutoExpiryJob.set(wait_until: Date.tomorrow.midnight).perform_later(account) + end end diff --git a/app/jobs/import_work_from_purl_job.rb b/app/jobs/import_work_from_purl_job.rb deleted file mode 100644 index c7dc351aa..000000000 --- a/app/jobs/import_work_from_purl_job.rb +++ /dev/null @@ -1,97 +0,0 @@ -# frozen_string_literal: true - -require 'stanford' -# Import works from Purl/stacks services at Stanford -# -# Example usage: -# log = Hyrax::Operation.create!(user: current_user, -# operation_type: "Import Purl Metadata") -# ImportWorkFromPurlJob.perform_later(current_user, -# 'abcd1234xxxx', -# log) -class ImportWorkFromPurlJob < ApplicationJob - queue_as :ingest - - before_enqueue do |job| - log = job.arguments.last - log.pending_job(self) - end - - # This copies metadata from the passed in attribute to all of the works that - # are members of the given upload set - # @param [User] user - # @param [String] druid - # @param [Hyrax::Operation] log - def perform(user, druid, log) - xml = Stanford::Importer::PurlRetriever.get(druid) - parser = Stanford::Importer::PurlParser.new(xml) - attributes = process_attributes(parser.attributes) - model = model_to_create(attributes) - - CreateWorkJob.perform_later(user, model, attributes, log) - rescue Faraday::ResourceNotFound - Rails.logger.error "Unable to fetch #{druid} from purl." - end - - private - - def process_attributes(attributes) - # We're pruning off :form_of_work, :record_origin, :created_attributes, :identifiers - attributes = attributes.slice(*attributes_to_keep) - # rename :location to :based_near - attributes[:based_near] = attributes.delete(:location) - - # rename :rights to :license - attributes[:license] = attributes.delete(:rights) - - attributes[:collection][:collection_type] ||= Hyrax::CollectionType.find_or_create_default_collection_type - - process_collection(attributes) - filenames = attributes.delete(:files) - attributes[:remote_files] = filenames.map do |name| - { url: "https://stacks.stanford.edu/file/druid:#{attributes[:id]}/#{name}", - file_name: name } - end - - attributes - end - - class_attribute :attributes_to_keep - self.attributes_to_keep = %i[title - description - subject - language - resource_type - location - rights - visibility - id - collection - files - collection_type] - - def process_collection(attributes) - # rename :collection to :member_of_collection_attributes - collection = attributes.delete(:collection) - - # Workaround for ActiveFedora #1186 - id = collection[:id] - begin - retries ||= 0 - Collection.create!(collection) unless Collection.exists?(id) - rescue Ldp::Conflict => e - ## Another process has likely beat us to the punch. Wait a bit and try again. - sleep(3) - retry if (retries += 1) < 3 - raise e - end - attributes[:member_of_collection_attributes] = [{ id: id }] - end - - # Override this method if you have a different rubric for choosing the model - # @param [Hash] attributes - # @return String the model to create - def model_to_create(_attributes) - GenericWork.model_name.name - end -end diff --git a/app/jobs/lease_auto_expiry_job.rb b/app/jobs/lease_auto_expiry_job.rb index 16f6bcf9c..fe21273ed 100644 --- a/app/jobs/lease_auto_expiry_job.rb +++ b/app/jobs/lease_auto_expiry_job.rb @@ -15,7 +15,7 @@ def perform(account) private - def reenqueue(account) - LeaseAutoExpiryJob.set(wait_until: Date.tomorrow.midnight).perform_later(account) - end + def reenqueue(account) + LeaseAutoExpiryJob.set(wait_until: Date.tomorrow.midnight).perform_later(account) + end end diff --git a/app/jobs/remove_solr_collection_job.rb b/app/jobs/remove_solr_collection_job.rb index a93eebeb9..2efbf2843 100644 --- a/app/jobs/remove_solr_collection_job.rb +++ b/app/jobs/remove_solr_collection_job.rb @@ -15,8 +15,8 @@ def perform(collection, connection_options, tenant_type = 'normal') private - def solr_client(connection_options) - # We remove the adapter, otherwise RSolr 2 will try to use it as a Faraday middleware - RSolr.connect(connection_options.without('adapter')) - end + def solr_client(connection_options) + # We remove the adapter, otherwise RSolr 2 will try to use it as a Faraday middleware + RSolr.connect(connection_options.without('adapter')) + end end diff --git a/app/mailers/hyku_mailer.rb b/app/mailers/hyku_mailer.rb index 924a0834d..9539011d7 100644 --- a/app/mailers/hyku_mailer.rb +++ b/app/mailers/hyku_mailer.rb @@ -8,7 +8,7 @@ def default_url_options private - def host_for_tenant - Account.find_by(tenant: Apartment::Tenant.current)&.cname || Account.admin_host - end + def host_for_tenant + Account.find_by(tenant: Apartment::Tenant.current)&.cname || Account.admin_host + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index c433ad198..80708e606 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -25,7 +25,7 @@ class Ability self.ability_logic += %i[everyone_can_create_curation_concerns] end - # OVERRIDE METHOD from blacklight-access_controls v0.6.2 + # OVERRIDE METHOD from blacklight-access_controls v6.0.1 # # NOTE: DO NOT RENAME THIS METHOD - it is required for permissions to function properly. # diff --git a/app/models/account.rb b/app/models/account.rb index 449795ac3..9dcfc3e9b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true # Customer organization account +# rubocop:disable Metrics/ClassLength class Account < ApplicationRecord include AccountEndpoints include AccountSettings @@ -110,6 +111,8 @@ def switch_host!(cname) Hyrax::Engine.routes.default_url_options[:host] = cname end + DEFAULT_FILE_CACHE_STORE = ENV.fetch('HYKU_CACHE_ROOT', '/app/samvera/file_cache') + def setup_tenant_cache(is_enabled) Rails.application.config.action_controller.perform_caching = is_enabled ActionController::Base.perform_caching = is_enabled @@ -117,7 +120,7 @@ def setup_tenant_cache(is_enabled) if is_enabled Rails.application.config.cache_store = :redis_cache_store, { url: Redis.current.id } else - Rails.application.config.cache_store = :file_store, ENV.fetch('HYKU_CACHE_ROOT', '/app/samvera/file_cache') + Rails.application.config.cache_store = :file_store, DEFAULT_FILE_CACHE_STORE end # rubocop:enable Style/ConditionalAssignment Rails.cache = ActiveSupport::Cache.lookup_store(Rails.application.config.cache_store) @@ -144,3 +147,4 @@ def cache_api? cache_api end end +# rubocop:enable Metrics/ClassLength diff --git a/app/models/collection.rb b/app/models/collection.rb index 39bd58492..2b2298fd8 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -8,6 +8,7 @@ class Collection < ActiveFedora::Base self.indexer = CollectionIndexer after_update :remove_featured, if: proc { |collection| collection.private? } after_destroy :remove_featured + prepend OrderAlready.for(:creator) def remove_featured FeaturedCollection.where(collection_id: id).destroy_all diff --git a/app/models/concerns/account_cname.rb b/app/models/concerns/account_cname.rb index 0306a1110..8c13d5630 100644 --- a/app/models/concerns/account_cname.rb +++ b/app/models/concerns/account_cname.rb @@ -12,7 +12,7 @@ module AccountCname # @raise [ArgumentError] if piece contains a trailing dot def default_cname(piece) return unless piece - raise ArgumentError, "param '#{piece}' must not contain trailing dots" if piece =~ /\.\Z/ + raise ArgumentError, "param '#{piece}' must not contain trailing dots" if /\.\Z/.match?(piece) # rubocop:disable Style/FormatStringToken default_host = ENV.fetch('HYKU_DEFAULT_HOST', "%{tenant}.#{admin_host}") # rubocop:enable Style/FormatStringToken @@ -51,7 +51,7 @@ def cname=(value) private - def default_cname(piece = name) - self.class.default_cname(piece) - end + def default_cname(piece = name) + self.class.default_cname(piece) + end end diff --git a/app/models/concerns/account_settings.rb b/app/models/concerns/account_settings.rb index 5cd2458c0..85e98fd5d 100644 --- a/app/models/concerns/account_settings.rb +++ b/app/models/concerns/account_settings.rb @@ -3,6 +3,7 @@ # All settings have a presedence order as follows # Per Tenant Setting > ENV['HYKU_SETTING_NAME'] > ENV['HYRAX_SETTING_NAME'] > default +# rubocop:disable Metrics/ModuleLength module AccountSettings extend ActiveSupport::Concern # rubocop:disable Metrics/BlockLength @@ -79,6 +80,7 @@ def setting(name, args) end end + # rubocop:disable Metrics/MethodLength def solr_collection_options { async: nil, @@ -99,6 +101,7 @@ def solr_collection_options snitch: nil } end + # rubocop:disable Metrics/MethodLength end # rubocop:enable Metrics/BlockLength @@ -112,80 +115,81 @@ def live_settings private - def set_type(value, to_type) - case to_type - when 'array' - value.is_a?(String) ? value.split(',') : Array.wrap(value) - when 'boolean' - ActiveModel::Type::Boolean.new.cast(value) - when 'hash' - value.is_a?(String) ? JSON.parse(value) : value - when 'string' - value.to_s - end + def set_type(value, to_type) + case to_type + when 'array' + value.is_a?(String) ? value.split(',') : Array.wrap(value) + when 'boolean' + ActiveModel::Type::Boolean.new.cast(value) + when 'hash' + value.is_a?(String) ? JSON.parse(value) : value + when 'string' + value.to_s end + end - def validate_email_format - return if settings['email_format'].blank? - settings['email_format'].each do |email| - errors.add(:email_format) unless email.match?(/@\S*\.\S*/) - end + def validate_email_format + return if settings['email_format'].blank? + settings['email_format'].each do |email| + errors.add(:email_format) unless email.match?(/@\S*\.\S*/) end + end - def validate_contact_emails - ['weekly_email_list', 'monthly_email_list', 'yearly_email_list'].each do |key| - next if settings[key].blank? - settings[key].each do |email| - errors.add(:"#{key}") unless email.match?(URI::MailTo::EMAIL_REGEXP) - end + def validate_contact_emails + ['weekly_email_list', 'monthly_email_list', 'yearly_email_list'].each do |key| + next if settings[key].blank? + settings[key].each do |email| + errors.add(:"#{key}") unless email.match?(URI::MailTo::EMAIL_REGEXP) end end + end - def initialize_settings - return true unless self.class.column_names.include?('settings') - set_smtp_settings - reload_library_config - end + def initialize_settings + return true unless self.class.column_names.include?('settings') + set_smtp_settings + reload_library_config + end - def set_smtp_settings - current_smtp_settings = settings&.[]("smtp_settings").presence || {} - self.smtp_settings = current_smtp_settings.with_indifferent_access.reverse_merge!( - PerTenantSmtpInterceptor.available_smtp_fields.each_with_object("").to_h - ) + def set_smtp_settings + current_smtp_settings = settings&.[]("smtp_settings").presence || {} + self.smtp_settings = current_smtp_settings.with_indifferent_access.reverse_merge!( + PerTenantSmtpInterceptor.available_smtp_fields.each_with_object("").to_h + ) + end + + # rubocop:disable Metrics/AbcSize + def reload_library_config + Hyrax.config do |config| + config.contact_email = contact_email + config.geonames_username = geonames_username + config.uploader[:maxFileSize] = file_size_limit.to_i end - def reload_library_config - Hyrax.config do |config| - config.contact_email = contact_email - config.analytics = google_analytics_id.present? - config.google_analytics_id = google_analytics_id if google_analytics_id.present? - config.geonames_username = geonames_username - config.uploader[:maxFileSize] = file_size_limit - end + Devise.mailer_sender = contact_email - Devise.mailer_sender = contact_email - - if s3_bucket.present? - CarrierWave.configure do |config| - config.storage = :aws - config.aws_bucket = s3_bucket - config.aws_acl = 'bucket-owner-full-control' - end - elsif !file_acl - CarrierWave.configure do |config| - config.permissions = nil - config.directory_permissions = nil - end - else - CarrierWave.configure do |config| - config.storage = :file - config.permissions = 420 - config.directory_permissions = 493 - end + if s3_bucket.present? + CarrierWave.configure do |config| + config.storage = :aws + config.aws_bucket = s3_bucket + config.aws_acl = 'bucket-owner-full-control' + end + elsif !file_acl + CarrierWave.configure do |config| + config.permissions = nil + config.directory_permissions = nil + end + else + CarrierWave.configure do |config| + config.storage = :file + config.permissions = 420 + config.directory_permissions = 493 end - - return unless ssl_configured - ActionMailer::Base.default_url_options ||= {} - ActionMailer::Base.default_url_options[:protocol] = 'https' end + + return unless ssl_configured + ActionMailer::Base.default_url_options ||= {} + ActionMailer::Base.default_url_options[:protocol] = 'https' + end + # rubocop:enable Metrics/AbcSize end +# rubocop:enable Metrics/ModuleLength diff --git a/app/models/concerns/account_switch.rb b/app/models/concerns/account_switch.rb index 7c5a02f00..613dbec60 100644 --- a/app/models/concerns/account_switch.rb +++ b/app/models/concerns/account_switch.rb @@ -6,11 +6,12 @@ module AccountSwitch DOMAIN_REGEXP = %r{^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,8}(:[0-9]{1,5})?(/.*)?$}ix class_methods do + # rubocop:disable Metrics/MethodLength def switch!(cname_or_name_or_account) account = if cname_or_name_or_account.is_a?(Account) cname_or_name_or_account # is it a domain name? - elsif cname_or_name_or_account =~ DOMAIN_REGEXP + elsif DOMAIN_REGEXP.match?(cname_or_name_or_account) Account.joins(:domain_names).find_by(domain_names: { is_active: true, cname: Account.canonical_cname(cname_or_name_or_account) @@ -26,6 +27,7 @@ def switch!(cname_or_name_or_account) Rails.logger.info "It looks like we're in single tenant mode. No tenant found for #{cname_or_name_or_account}" end end + # rubocop:enable Metrics/MethodLength end def switch!(cname_or_name_or_account) diff --git a/app/models/concerns/hyrax/ability/collection_ability.rb b/app/models/concerns/hyrax/ability/collection_ability.rb index 3af46e0c2..612e1070a 100644 --- a/app/models/concerns/hyrax/ability/collection_ability.rb +++ b/app/models/concerns/hyrax/ability/collection_ability.rb @@ -1,12 +1,15 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 Alter abilities for Groups with Roles feature +# OVERRIDE Hyrax v5.0.0rc2 Alter abilities for Groups with Roles feature module Hyrax module Ability + # rubocop:disable Metrics/ModuleLength module CollectionAbility # rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/BlockLength # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/PerceivedComplexity + # rubocop:disable Metrics/CyclomaticComplexity def collection_abilities models = [Hyrax::PcdmCollection, Hyrax.config.collection_class].uniq if admin? @@ -157,6 +160,9 @@ def collection_roles # rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/BlockLength # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/PerceivedComplexity + # rubocop:enable Metrics/CyclomaticComplexity end + # rubocop:enable Metrics/ModuleLength end end diff --git a/app/models/concerns/hyrax/ability/solr_document_ability.rb b/app/models/concerns/hyrax/ability/solr_document_ability.rb index 2196f28bd..1248eefbc 100644 --- a/app/models/concerns/hyrax/ability/solr_document_ability.rb +++ b/app/models/concerns/hyrax/ability/solr_document_ability.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 Alter abilities for Groups with Roles feature +# OVERRIDE Hyrax v5.0.0rc2 Alter abilities for Groups with Roles feature module Hyrax module Ability module SolrDocumentAbility + # rubocop:disable Metrics/MethodLength def solr_document_abilities if admin? can [:manage], ::SolrDocument @@ -27,6 +28,7 @@ def solr_document_abilities end end end + # rubocop:enable Metrics/MethodLength end end end diff --git a/app/models/concerns/hyrax/ability/work_ability.rb b/app/models/concerns/hyrax/ability/work_ability.rb index b025c979c..9d7daebc0 100644 --- a/app/models/concerns/hyrax/ability/work_ability.rb +++ b/app/models/concerns/hyrax/ability/work_ability.rb @@ -32,7 +32,7 @@ def admin_set_with_deposit? return false if ids.empty? - Hyrax.custom_queries.find_ids_by_model(model: Hyrax::AdministrativeSet, ids: ids).any? + Hyrax.custom_queries.find_ids_by_model(model: Hyrax::AdministrativeSet, ids:).any? end end end diff --git a/app/models/content_block.rb b/app/models/content_block.rb index c9e72b26e..b4f291f43 100644 --- a/app/models/content_block.rb +++ b/app/models/content_block.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.0 to add home_text to registry -# and getter/setter methods - Adding themes +# OVERRIDE Hyrax v5.0.0rc to add home_text to registry and getter/setter methods - Adding themes +# NOTE: This class inherits from ApplicationRecord while Hyrax's version inherits from ActiveRecord::Base +# so we cannot use the decorator pattern to override the methods. +# rubocop:disable Metrics/ClassLength class ContentBlock < ApplicationRecord # The keys in this registry are "public" names for collaborator # objects, and the values are reserved names of ContentBlock @@ -16,7 +18,9 @@ class ContentBlock < ApplicationRecord help: :help_page, terms: :terms_page, agreement: :agreement_page, - home_text: :home_text + home_text: :home_text, + homepage_about_section_heading: :homepage_about_section_heading, + homepage_about_section_content: :homepage_about_section_content }.freeze # NOTE: method defined outside the metaclass wrapper below because @@ -41,7 +45,7 @@ def whitelisted?(key) # # @return [Object] either the named block's value or the fallback_value. def block_for(name:, fallback_value: false) - block = ContentBlock.find_by(name: name) + block = ContentBlock.find_by(name:) block&.value.presence || fallback_value end @@ -50,7 +54,7 @@ def block_for(name:, fallback_value: false) # @param name [#to_s] the named content block # @param value [Object] the value to update the given content block def update_block(name:, value:) - find_or_create_by(name: name.to_s).update!(value: value) + find_or_create_by(name: name.to_s).update!(value:) end def registered?(key) @@ -62,7 +66,7 @@ def marketing_text end def marketing_text=(value) - marketing_text.update(value: value) + marketing_text.update(value:) end def announcement_text @@ -70,7 +74,7 @@ def announcement_text end def announcement_text=(value) - announcement_text.update(value: value) + announcement_text.update(value:) end def featured_researcher @@ -78,7 +82,7 @@ def featured_researcher end def featured_researcher=(value) - featured_researcher.update(value: value) + featured_researcher.update(value:) end # OVERRIDE Hyrax v3.4.0 to add home_text getter/setter methods - Adding themes @@ -87,7 +91,23 @@ def home_text end def home_text=(value) - home_text.update(value: value) + home_text.update(value:) + end + + def homepage_about_section_heading + find_or_create_by(name: 'homepage_about_section_heading') + end + + def homepage_about_section_heading=(value) + homepage_about_section_heading.update(value:) + end + + def homepage_about_section_content + find_or_create_by(name: 'homepage_about_section_content') + end + + def homepage_about_section_content=(value) + homepage_about_section_content.update(value:) end def about_page @@ -95,7 +115,7 @@ def about_page end def about_page=(value) - about_page.update(value: value) + about_page.update(value:) end def agreement_page @@ -104,7 +124,7 @@ def agreement_page end def agreement_page=(value) - agreement_page.update(value: value) + agreement_page.update(value:) end def help_page @@ -112,7 +132,7 @@ def help_page end def help_page=(value) - help_page.update(value: value) + help_page.update(value:) end def terms_page @@ -121,7 +141,7 @@ def terms_page end def terms_page=(value) - terms_page.update(value: value) + terms_page.update(value:) end def default_agreement_text @@ -141,3 +161,4 @@ def default_terms_text end end end +# rubocop:enable Metrics/ClassLength diff --git a/app/models/fcrepo_endpoint.rb b/app/models/fcrepo_endpoint.rb index 7b02ff281..cd5a6e88b 100644 --- a/app/models/fcrepo_endpoint.rb +++ b/app/models/fcrepo_endpoint.rb @@ -27,7 +27,7 @@ def ping def remove! switch! # Preceding slash must be removed from base_path when calling delete() - path = base_path.sub!(%r{^/}, '') + path = base_path.sub(%r{^/}, '') ActiveFedora.fedora.connection.delete(path) destroy end diff --git a/app/models/featured_collection_list.rb b/app/models/featured_collection_list.rb index 1de617815..5a1ff6363 100644 --- a/app/models/featured_collection_list.rb +++ b/app/models/featured_collection_list.rb @@ -30,24 +30,24 @@ def featured_collections private - def add_solr_document_to_collections - collection_presenters.each do |presenter| - collection_with_id(presenter.id).presenter = presenter - end + def add_solr_document_to_collections + collection_presenters.each do |presenter| + collection_with_id(presenter.id).presenter = presenter end + end - def ids - @collections.pluck(:collection_id) - end + def ids + @collections.pluck(:collection_id) + end - def collection_presenters - ability = nil - Hyrax::PresenterFactory.build_for(ids: ids, - presenter_class: Hyku::WorkShowPresenter, - presenter_args: ability) - end + def collection_presenters + ability = nil + Hyrax::PresenterFactory.build_for(ids:, + presenter_class: Hyku::WorkShowPresenter, + presenter_args: ability) + end - def collection_with_id(id) - @collections.find { |c| c.collection_id == id } - end + def collection_with_id(id) + @collections.find { |c| c.collection_id == id } + end end diff --git a/app/models/generic_work.rb b/app/models/generic_work.rb index f69aae6ab..4c45fad1e 100644 --- a/app/models/generic_work.rb +++ b/app/models/generic_work.rb @@ -12,4 +12,6 @@ class GenericWork < ActiveFedora::Base validates :title, presence: { message: 'Your work must have a title.' } self.indexer = GenericWorkIndexer + + prepend OrderAlready.for(:creator) end diff --git a/app/models/hydra/access_controls/embargo_decorator.rb b/app/models/hydra/access_controls/embargo_decorator.rb index 6d1bed4ed..9daf716e3 100644 --- a/app/models/hydra/access_controls/embargo_decorator.rb +++ b/app/models/hydra/access_controls/embargo_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hydra-access-controls 12.0.1 +# OVERRIDE Hydra-access-controls v12.1.0 # Fix releasing embargos on the day they are expired - this solves a 1 second bug around how # midnights are calculated, which causes day of embargos to incorrectly set the permissions to private module Hydra diff --git a/app/models/hydra/access_controls/lease_decorator.rb b/app/models/hydra/access_controls/lease_decorator.rb index 971f7f58b..37ab3b856 100644 --- a/app/models/hydra/access_controls/lease_decorator.rb +++ b/app/models/hydra/access_controls/lease_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hydra-access-controls 12.0.1 +# OVERRIDE Hydra-access-controls 12.1.0 # Fix releasing leases on the day they are expired - this solves a 1 second bug around how # midnights are calculated, which causes day of leases to incorrectly set the permissions to private module Hydra diff --git a/app/models/hyrax/collection_type_participant_decorator.rb b/app/models/hyrax/collection_type_participant_decorator.rb index c64b667d2..164f101a1 100644 --- a/app/models/hyrax/collection_type_participant_decorator.rb +++ b/app/models/hyrax/collection_type_participant_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 Expand functionality for Groups with Roles feature +# OVERRIDE Hyrax v5.0.0rc2 Expand functionality for Groups with Roles feature module Hyrax module CollectionTypeParticipantDecorator # OVERRIDE: #titleize agent_id for groups since we are displaying their humanized names in the dropdown diff --git a/app/models/hyrax/contact_form.rb b/app/models/hyrax/contact_form.rb deleted file mode 100644 index fc03c74ee..000000000 --- a/app/models/hyrax/contact_form.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax 3.4.0 to override the mail to -module Hyrax - class ContactForm - include ActiveModel::Model - attr_accessor :contact_method, :category, :name, :email, :subject, :message - validates :email, :category, :name, :subject, :message, presence: true - validates :email, format: /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i, allow_blank: true - - # - can't use this without ActiveRecord::Base - # validates_inclusion_of :category, in: self.class.issue_types_for_locale - - # They should not have filled out the `contact_method' field. That's there to prevent spam. - def spam? - contact_method.present? - end - - # Declare the e-mail headers. It accepts anything the mail method - # in ActionMailer accepts. - ###### OVERRODE the to: field to add the Tenant's email, first - def contact_email - Site.account.contact_email_to - end - - def headers - ## OVERRIDE Hyrax 3.4.0 send the mail 'from' the submitter, which doesn't work on most smtp transports - { - subject: "#{Site.account.email_subject_prefix} #{email} #{subject}", - to: contact_email, - from: Site.account.contact_email, - reply_to: email - } - end - - def self.issue_types_for_locale - I18n.t('hyrax.contact_form.issue_types').values.select(&:present?) - end - end -end diff --git a/app/models/hyrax/contact_form_decorator.rb b/app/models/hyrax/contact_form_decorator.rb new file mode 100644 index 000000000..27cbf3fb0 --- /dev/null +++ b/app/models/hyrax/contact_form_decorator.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax v5.0.0rc2 to override the mail to +module Hyrax + module ContactFormDecorator + # Declare the e-mail headers. It accepts anything the mail method + # in ActionMailer accepts. + ###### OVERRIDE the to: field to add the Tenant's email, first + def contact_email + Site.account.contact_email_to + end + + def headers + ## OVERRIDE Hyrax 3.4.0 send the mail 'from' the submitter, which doesn't work on most smtp transports + { + subject: "#{Site.account.email_subject_prefix} #{email} #{subject}", + to: contact_email, + from: Site.account.contact_email, + reply_to: email + } + end + end +end + +Hyrax::ContactForm.prepend(Hyrax::ContactFormDecorator) diff --git a/app/models/hyrax/group.rb b/app/models/hyrax/group.rb index bc33f2d73..640498f77 100644 --- a/app/models/hyrax/group.rb +++ b/app/models/hyrax/group.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 Expand functionality for Groups with Roles Feature +# OVERRIDE Hyrax v5.0.0rc2 Expand functionality for Groups with Roles Feature # @see https://github.com/samvera/hyku/wiki/Groups-with-Roles-Feature module Hyrax class Group < ApplicationRecord @@ -16,6 +16,26 @@ class Group < ApplicationRecord before_destroy :can_destroy? after_destroy :remove_all_members + ## + # What is going on here? In Hyrax proper, the Group model is a plain old Ruby object (PORO). In + # Hyku, the {Hyrax::Group} is based on ActiveRecord. + # + # The Hyrax version instantiates with a single string parameter. Importantly, we want to re-use + # the Hyrax::Workflow::PermissionQuery logic, without re-writing it. In particular we want to + # consider the Hyrax::Workflow::PermissionQuery#scope_processing_agents_for which casts the + # group to a Sipity::Agent + # + # @see https://github.com/samvera/hyrax/blob/main/app/models/hyrax/group.rb + # @see https://github.com/samvera/hyrax/blob/main/app/services/hyrax/workflow/permission_query.rb + def self.new(*args) + # This logic path is likely coming from Hyrax specific code; in which it expects a string. + if args.size == 1 && args.first.is_a?(String) + find_by(name: args.first) || super(name: args.first) + else + super + end + end + def self.name_prefix DEFAULT_NAME_PREFIX end @@ -43,7 +63,7 @@ def search_members(query, member_class: DEFAULT_MEMBER_CLASS) if query.present? && member_class == DEFAULT_MEMBER_CLASS members.where("email LIKE :q OR display_name LIKE :q", q: "%#{query}%") else - members(member_class: member_class) + members(member_class:) end end @@ -85,7 +105,7 @@ def default_group? def description_label label = description || I18n.t("hyku.admin.groups.description.#{name}") - return '' if label =~ /^translation missing:/ + return '' if /^translation missing:/.match?(label) label end @@ -98,22 +118,22 @@ def has_site_role?(role_name) # rubocop:disable Naming/PredicateName private - def can_destroy? - return false if default_group? + def can_destroy? + return false if default_group? - true - end + true + end - def remove_all_members - members.map { |m| m.remove_role(MEMBERSHIP_ROLE, self) } - end + def remove_all_members + members.map { |m| m.remove_role(MEMBERSHIP_ROLE, self) } + end - def sipity_agent - Sipity::Agent.find_by(proxy_for_id: name, proxy_for_type: self.class.name) - end + def sipity_agent + Sipity::Agent.find_by(proxy_for_id: name, proxy_for_type: self.class.name) + end - def create_sipity_agent! - Sipity::Agent.create!(proxy_for_id: name, proxy_for_type: self.class.name) - end + def create_sipity_agent! + Sipity::Agent.create!(proxy_for_id: name, proxy_for_type: self.class.name) + end end end diff --git a/app/models/hyrax/permission_template_access_decorator.rb b/app/models/hyrax/permission_template_access_decorator.rb index 7ca6bb32b..f6f6fa479 100644 --- a/app/models/hyrax/permission_template_access_decorator.rb +++ b/app/models/hyrax/permission_template_access_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# OVERRIDE Hyrax v3.4.2 #titleize agent_id for groups since we are displaying their humanized names in the dropdown +# OVERRIDE Hyrax v5.0.0rc2 #titleize agent_id for groups since we are displaying their humanized names in the dropdown module Hyrax module PermissionTemplateAccessDecorator def label diff --git a/app/models/image.rb b/app/models/image.rb index 51afe7599..e259048b3 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -19,6 +19,8 @@ class Image < ActiveFedora::Base include ::Hyrax::BasicMetadata self.indexer = ImageIndexer + prepend OrderAlready.for(:creator) + # Change this to restrict which works can be added as a child. # self.valid_child_concerns = [] validates :title, presence: { message: 'Your work must have a title.' } diff --git a/app/models/nil_fcrepo_endpoint.rb b/app/models/nil_fcrepo_endpoint.rb index d72614517..d833c0f42 100644 --- a/app/models/nil_fcrepo_endpoint.rb +++ b/app/models/nil_fcrepo_endpoint.rb @@ -15,7 +15,7 @@ def base_path private - def options - { url: 'http://127.0.0.1:99999/nil_fcrepo_endpoint' } - end + def options + { url: 'http://127.0.0.1:99999/nil_fcrepo_endpoint' } + end end diff --git a/app/models/nil_solr_endpoint.rb b/app/models/nil_solr_endpoint.rb index 7a16634fc..9dd11f166 100644 --- a/app/models/nil_solr_endpoint.rb +++ b/app/models/nil_solr_endpoint.rb @@ -13,16 +13,16 @@ def url private - # Return an RSolr connection, that points at an invalid endpoint - # Note: We could have returned a NilRSolrConnection here, but Blacklight - # makes it's own RSolr connection, so we'd end up with an RSolr connection in - # blacklight anyway. - def connection - RSolr.connect(connection_options) - end + # Return an RSolr connection, that points at an invalid endpoint + # Note: We could have returned a NilRSolrConnection here, but Blacklight + # makes it's own RSolr connection, so we'd end up with an RSolr connection in + # blacklight anyway. + def connection + RSolr.connect(connection_options) + end - # Return options that will never return a valid connection. - def connection_options - { url: 'http://127.0.0.1:99999/nil_solr_endpoint' } - end + # Return options that will never return a valid connection. + def connection_options + { url: 'http://127.0.0.1:99999/nil_solr_endpoint' } + end end diff --git a/app/models/redis_endpoint.rb b/app/models/redis_endpoint.rb index b6899cf98..3cd68f707 100644 --- a/app/models/redis_endpoint.rb +++ b/app/models/redis_endpoint.rb @@ -21,20 +21,14 @@ def ping # Remove all the keys in Redis in this namespace, then destroy the record def remove! switch! - # Redis::Namespace currently doesn't support flushall or flushdb. - # See https://github.com/resque/redis-namespace/issues/56 - # So, instead we select all keys in current namespace and delete - keys = redis_instance.keys '*' - return if keys.empty? - # Delete in slices to avoid "stack level too deep" errors for large numbers of keys - # See https://github.com/redis/redis-rb/issues/122 - keys.each_slice(1000) { |key_slice| redis_instance.del(*key_slice) } + # redis-namespace v1.10.0 introduced clear https://github.com/resque/redis-namespace/pull/202 + redis_instance.clear destroy end private - def redis_instance - Hyrax::RedisEventStore.instance - end + def redis_instance + Hyrax::RedisEventStore.instance + end end diff --git a/app/models/role.rb b/app/models/role.rb index 4b5c4eefd..f30b58e30 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -21,7 +21,7 @@ class Role < ApplicationRecord def description_label label = description || I18n.t("hyku.admin.roles.description.#{name}") - return '' if label =~ /^translation missing:/ + return '' if /^translation missing:/.match?(label) label end @@ -29,13 +29,13 @@ def description_label def set_sort_value self.sort_value = if name == 'admin' 0 - elsif name =~ /manager/ + elsif /manager/.match?(name) 1 - elsif name =~ /editor/ + elsif /editor/.match?(name) 2 - elsif name =~ /depositor/ + elsif /depositor/.match?(name) 3 - elsif name =~ /reader/ + elsif /reader/.match?(name) 4 else 99 diff --git a/app/models/search_builder.rb b/app/models/search_builder.rb index ad50b6e1e..4410a5bc8 100644 --- a/app/models/search_builder.rb +++ b/app/models/search_builder.rb @@ -2,6 +2,10 @@ class SearchBuilder < Blacklight::SearchBuilder include Blacklight::Solr::SearchBuilderBehavior + include BlacklightRangeLimit::RangeLimitBuilder + include BlacklightAdvancedSearch::AdvancedSearchBuilder include Hydra::AccessControlsEnforcement include Hyrax::SearchFilters + + self.default_processor_chain += %i[add_advanced_parse_q_to_solr add_advanced_search_to_solr] end diff --git a/app/models/site.rb b/app/models/site.rb index 777bf1a0b..b250a193c 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -51,26 +51,26 @@ def admin_emails=(emails) private - # Add/invite admins via email address - # @param [Array<String>] Array of user emails - def add_admins_by_email(emails) - # For users that already have accounts, add to role immediately - existing_emails = User.where(email: emails).map do |u| - u.add_role :admin, self - u.email - end - # For new users, send invitation and add to role - (emails - existing_emails).each do |email| - u = User.invite!(email: email) - u.add_role :admin, self - end + # Add/invite admins via email address + # @param [Array<String>] Array of user emails + def add_admins_by_email(emails) + # For users that already have accounts, add to role immediately + existing_emails = User.where(email: emails).map do |u| + u.add_role :admin, self + u.email + end + # For new users, send invitation and add to role + (emails - existing_emails).each do |email| + u = User.invite!(email:) + u.add_role :admin, self end + end - # Remove specific administrators - # @param [Array<String>] Array of user emails - def remove_admins_by_email(emails) - User.where(email: emails).find_each do |u| - u.remove_role :admin, self - end + # Remove specific administrators + # @param [Array<String>] Array of user emails + def remove_admins_by_email(emails) + User.where(email: emails).find_each do |u| + u.remove_role :admin, self end + end end diff --git a/app/models/solr_endpoint.rb b/app/models/solr_endpoint.rb index be217ab81..3e90a6812 100644 --- a/app/models/solr_endpoint.rb +++ b/app/models/solr_endpoint.rb @@ -29,6 +29,9 @@ def switch! # Remove the solr collection then destroy this record def remove! + # NOTE: Other end points first call switch!; is that an oversight? Perhaps not as we're relying + # on a scheduled job to do the destructive work. + # Spin off as a job, so that it can fail and be retried separately from the other logic. if account.search_only? RemoveSolrCollectionJob.perform_later(collection, connection_options, 'cross_search_tenant') diff --git a/app/models/user.rb b/app/models/user.rb index 7bfdd16cf..4a1beb3ab 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,14 +9,11 @@ class User < ApplicationRecord include Hyrax::User include Hyrax::UserUsageStats - attr_accessible :email, :password, :password_confirmation if Blacklight::Utils.needs_attr_accessible? # Connects this user object to Blacklights Bookmarks. include Blacklight::User # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :invitable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, - :omniauthable, omniauth_providers: %i[saml openid_connect cas] + devise(*Hyku::Application.user_devise_parameters) after_create :add_default_group_membership! @@ -25,7 +22,7 @@ def self.default_scope where(guest: false) end - scope :for_repository, -> { + scope :for_repository, lambda { joins(:roles) } @@ -49,11 +46,15 @@ def to_s email end + # rubocop:disable Naming/PredicateName def is_admin + # rubocop:enable Naming/PredicateName has_role?(:admin) || has_role?(:admin, Site.instance) end + # rubocop:disable Naming/PredicateName def is_superadmin + # rubocop:enable Naming/PredicateName has_role? :superadmin end diff --git a/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb b/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb index 8348c245f..277f902a8 100644 --- a/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb +++ b/app/presenters/concerns/hyrax/iiif_av/displays_content_decorator.rb @@ -8,82 +8,84 @@ module IiifAv # request.base_url => hostname # also to remove #auth_service since it was not working for now module DisplaysContentDecorator - private + def solr_document + defined?(super) ? super : object + end - def solr_document - defined?(super) ? super : object - end + def current_ability + defined?(super) ? super : @ability + end - def current_ability - defined?(super) ? super : @ability - end + def request + Request.new(base_url: hostname) + end - Request = Struct.new(:base_url, keyword_init: true) + private - def request - Request.new(base_url: hostname) - end + Request = Struct.new(:base_url, keyword_init: true) - def image_content - return nil unless latest_file_id - url = Hyrax.config.iiif_image_url_builder.call( - latest_file_id, - request.base_url, - Hyrax.config.iiif_image_size_default, - solr_document.mime_type - ) + def image_content + return nil unless latest_file_id + url = Hyrax.config.iiif_image_url_builder.call( + latest_file_id, + request.base_url, + Hyrax.config.iiif_image_size_default, + solr_document.mime_type + ) - # Serving up only prezi 3 - image_content_v3(url) - end + # Serving up only prezi 3 + image_content_v3(url) + end - def video_display_content(_url, label = '') - width = solr_document.width&.try(:to_i) || 320 - height = solr_document.height&.try(:to_i) || 240 - duration = conformed_duration_in_seconds - IIIFManifest::V3::DisplayContent.new( - Hyrax::IiifAv::Engine.routes.url_helpers.iiif_av_content_url( - solr_document.id, - label: label, - host: request.base_url - ), - label: label, - width: width, - height: height, - duration: duration, - type: 'Video', - format: solr_document.mime_type - ) - end + # rubocop:disable Metrics/MethodLength + def video_display_content(_url, label = '') + width = solr_document.width&.try(:to_i) || 320 + height = solr_document.height&.try(:to_i) || 240 + duration = conformed_duration_in_seconds + IIIFManifest::V3::DisplayContent.new( + Hyrax::IiifAv::Engine.routes.url_helpers.iiif_av_content_url( + solr_document.id, + label:, + host: request.base_url + ), + label:, + width:, + height:, + duration:, + type: 'Video', + format: solr_document.mime_type + ) + end + # rubocop:enable Metrics/MethodLength - def audio_display_content(_url, label = '') - duration = conformed_duration_in_seconds - IIIFManifest::V3::DisplayContent.new( - Hyrax::IiifAv::Engine.routes.url_helpers.iiif_av_content_url( - solr_document.id, - label: label, - host: request.base_url - ), - label: label, - duration: duration, - type: 'Sound', - format: solr_document.mime_type - ) - end + def audio_display_content(_url, label = '') + duration = conformed_duration_in_seconds + IIIFManifest::V3::DisplayContent.new( + Hyrax::IiifAv::Engine.routes.url_helpers.iiif_av_content_url( + solr_document.id, + label:, + host: request.base_url + ), + label:, + duration:, + type: 'Sound', + format: solr_document.mime_type + ) + end - def conformed_duration_in_seconds - if Array(solr_document.duration)&.first&.count(':') == 3 - # takes care of milliseconds like ["0:0:01:001"] - Time.zone.parse(Array(solr_document.duration).first.sub(/.*\K:/, '.')).seconds_since_midnight - elsif Array(solr_document.duration)&.first&.include?(':') - # if solr_document.duration evaluates to something like ["0:01:00"] which will get converted to seconds - Time.zone.parse(Array(solr_document.duration).first).seconds_since_midnight - else - # handles cases if solr_document.duration evaluates to something like ['25 s'] - Array(solr_document.duration).first.try(:to_f) - end || - 400.0 - end + def conformed_duration_in_seconds + if Array(solr_document.duration)&.first&.count(':') == 3 + # takes care of milliseconds like ["0:0:01:001"] + Time.zone.parse(Array(solr_document.duration).first.sub(/.*\K:/, '.')).seconds_since_midnight + elsif Array(solr_document.duration)&.first&.include?(':') + # if solr_document.duration evaluates to something like ["0:01:00"] which will get converted to seconds + Time.zone.parse(Array(solr_document.duration).first).seconds_since_midnight + else + # handles cases if solr_document.duration evaluates to something like ['25 s'] + Array(solr_document.duration).first.try(:to_f) + end || + 400.0 + end end end end diff --git a/app/presenters/hyku/admin/group/navigation_presenter.rb b/app/presenters/hyku/admin/group/navigation_presenter.rb index 7afaf6a9c..99d31daf1 100644 --- a/app/presenters/hyku/admin/group/navigation_presenter.rb +++ b/app/presenters/hyku/admin/group/navigation_presenter.rb @@ -20,76 +20,76 @@ def tabs private - attr_reader :group_id, :params + attr_reader :group_id, :params - def edit_tab - Tab.new( - name: I18n.t('hyku.admin.groups.nav.attributes'), - controller: 'admin/groups', - action: 'edit', - path: Rails.application.routes.url_helpers.edit_admin_group_path(group_id), - context: params - ) - end + def edit_tab + Tab.new( + name: I18n.t('hyku.admin.groups.nav.attributes'), + controller: 'admin/groups', + action: 'edit', + path: Rails.application.routes.url_helpers.edit_admin_group_path(group_id), + context: params + ) + end - def members_tab - Tab.new( - name: I18n.t('hyku.admin.groups.nav.members'), - controller: 'admin/group_users', - action: 'index', - path: Rails.application.routes.url_helpers.admin_group_users_path(group_id), - context: params - ) - end + def members_tab + Tab.new( + name: I18n.t('hyku.admin.groups.nav.members'), + controller: 'admin/group_users', + action: 'index', + path: Rails.application.routes.url_helpers.admin_group_users_path(group_id), + context: params + ) + end - def roles_tab - Tab.new( - name: I18n.t('hyku.admin.groups.nav.roles'), - controller: 'admin/group_roles', - action: 'index', - path: Rails.application.routes.url_helpers.admin_group_roles_path(group_id), - context: params - ) - end + def roles_tab + Tab.new( + name: I18n.t('hyku.admin.groups.nav.roles'), + controller: 'admin/group_roles', + action: 'index', + path: Rails.application.routes.url_helpers.admin_group_roles_path(group_id), + context: params + ) + end - def remove_tab - Tab.new( - name: I18n.t('hyku.admin.groups.nav.delete'), - controller: 'admin/groups', - action: 'remove', - path: Rails.application.routes.url_helpers.remove_admin_group_path(group_id), - context: params - ) - end + def remove_tab + Tab.new( + name: I18n.t('hyku.admin.groups.nav.delete'), + controller: 'admin/groups', + action: 'remove', + path: Rails.application.routes.url_helpers.remove_admin_group_path(group_id), + context: params + ) + end - def group_id_key - return :id if params.key?(:id) - return :group_id if params.key?(:group_id) - :key_not_found - end + def group_id_key + return :id if params.key?(:id) + return :group_id if params.key?(:group_id) + :key_not_found + end - class Tab - ACTIVE_CSS_CLASS = 'active' + class Tab + ACTIVE_CSS_CLASS = 'active' - attr_reader :name, :path, :action + attr_reader :name, :path, :action - def initialize(name:, controller:, action:, path:, context:) - @name = name - @controller = controller - @action = action - @path = path - @context = context - end + def initialize(name:, controller:, action:, path:, context:) + @name = name + @controller = controller + @action = action + @path = path + @context = context + end - def css_class - return ACTIVE_CSS_CLASS if context.fetch(:controller) == controller && context.fetch(:action) == action - '' - end + def css_class + return ACTIVE_CSS_CLASS if context.fetch(:controller) == controller && context.fetch(:action) == action + '' + end - private + private - attr_reader :controller, :context - end + attr_reader :controller, :context + end end end end diff --git a/app/presenters/hyku/collapsable_section_presenter.rb b/app/presenters/hyku/collapsable_section_presenter.rb index f513b56a0..b2a263e73 100644 --- a/app/presenters/hyku/collapsable_section_presenter.rb +++ b/app/presenters/hyku/collapsable_section_presenter.rb @@ -1,31 +1,32 @@ # frozen_string_literal: true module Hyku - # Draws a collapsable list widget using the Bootstrap 3 / Collapse.js plugin + # Draws a collapsable list widget using the Bootstrap 4 / Collapse.js plugin class CollapsableSectionPresenter < Hyrax::CollapsableSectionPresenter - # Override Hyrax 3.5.0 to pass in html_options + # Override Hyrax v5.0.0rc2 to pass in the title attribute # rubocop:disable Metrics/ParameterLists - def initialize(view_context:, text:, id:, icon_class:, open:, html_options: {}) + def initialize(view_context:, text:, id:, icon_class:, open:, title: nil) # rubocop:enable Metrics/ParameterLists - super(view_context: view_context, text: text, id: id, icon_class: icon_class, open: open) - @html_options = html_options + super(view_context:, text:, id:, icon_class:, open:) + @title = title end - attr_reader :html_options + attr_reader :title private - def button_tag - tag.a({ role: 'button', - class: "#{button_class}collapse-toggle", - data: { toggle: 'collapse' }, - href: "##{id}", - onclick: "toggleCollapse(this)", - 'aria-expanded' => open, - 'aria-controls' => id }.merge(html_options)) do - safe_join([tag.span('', class: icon_class, 'aria-hidden': true), - tag.span(text)], ' ') - end + def button_tag + tag.a(role: 'button', + class: "#{button_class}collapse-toggle nav-link", + data: { toggle: 'collapse' }, + href: "##{id}", + onclick: "toggleCollapse(this)", + 'aria-expanded' => open, + 'aria-controls' => id, + title:) do + safe_join([tag.span('', class: icon_class, 'aria-hidden': true), + tag.span(text)], ' ') end + end end end diff --git a/app/presenters/hyku/menu_presenter.rb b/app/presenters/hyku/menu_presenter.rb index 7ed0c9e8f..a0a6c7148 100644 --- a/app/presenters/hyku/menu_presenter.rb +++ b/app/presenters/hyku/menu_presenter.rb @@ -50,16 +50,16 @@ def show_task? end # Draw a collaspable menu section. The passed block should contain <li> items. - # Override Hyrax 3.5.0 to pass in html_options + # Override Hyrax v5.0.0rc2 to pass in title attribute # rubocop:disable Metrics/ParameterLists - def collapsable_section(text, id:, icon_class:, open:, **html_options, &block) + def collapsable_section(text, id:, icon_class:, title:, open:, &block) # rubocop:enable Metrics/ParameterLists - CollapsableSectionPresenter.new(view_context: view_context, - text: text, - id: id, - icon_class: icon_class, - open: open, - html_options: html_options).render(&block) + CollapsableSectionPresenter.new(view_context:, + text:, + id:, + icon_class:, + title:, + open:).render(&block) end end end diff --git a/app/presenters/hyku/work_show_presenter.rb b/app/presenters/hyku/work_show_presenter.rb index 12427bc41..857f7932e 100644 --- a/app/presenters/hyku/work_show_presenter.rb +++ b/app/presenters/hyku/work_show_presenter.rb @@ -46,9 +46,7 @@ def display_unfeature_collection_link? def collection_featured? # only look this up if it's not boolean; ||= won't work here - if @collection_featured.nil? - @collection_featured = FeaturedCollection.where(collection_id: solr_document.id).exists? - end + @collection_featured = FeaturedCollection.where(collection_id: solr_document.id).exists? if @collection_featured.nil? @collection_featured end @@ -68,23 +66,23 @@ def iiif_viewer? private - def iiif_media?(presenter: representative_presenter) - presenter.image? || presenter.video? || presenter.audio? || presenter.pdf? - end + def iiif_media?(presenter: representative_presenter) + presenter.image? || presenter.video? || presenter.audio? || presenter.pdf? + end - def members_include_viewable? - file_set_presenters.any? do |presenter| - iiif_media?(presenter: presenter) && current_ability.can?(:read, presenter.id) - end + def members_include_viewable? + file_set_presenters.any? do |presenter| + iiif_media?(presenter:) && current_ability.can?(:read, presenter.id) end + end - def extract_from_identifier(rgx) - if solr_document['identifier_tesim'].present? - ref = solr_document['identifier_tesim'].map do |str| - str.scan(rgx) - end + def extract_from_identifier(rgx) + if solr_document['identifier_tesim'].present? + ref = solr_document['identifier_tesim'].map do |str| + str.scan(rgx) end - ref end + ref + end end end diff --git a/app/presenters/hyrax/admin/users_presenter.rb b/app/presenters/hyrax/admin/users_presenter.rb index 17d2fc0ba..8d49fd538 100644 --- a/app/presenters/hyrax/admin/users_presenter.rb +++ b/app/presenters/hyrax/admin/users_presenter.rb @@ -34,10 +34,10 @@ def show_last_access? private - # Returns a list of users excluding the system users and guest_users - def search - ::User.registered.for_repository.without_system_accounts.uniq - end + # Returns a list of users excluding the system users and guest_users + def search + ::User.registered.for_repository.without_system_accounts.uniq + end end end end diff --git a/app/presenters/hyrax/collection_presenter_decorator.rb b/app/presenters/hyrax/collection_presenter_decorator.rb index c348e5888..ba04cadd2 100644 --- a/app/presenters/hyrax/collection_presenter_decorator.rb +++ b/app/presenters/hyrax/collection_presenter_decorator.rb @@ -49,19 +49,11 @@ def [](key) # @return String the access label (e.g. Manage, Deposit, View) def managed_access # OVERRIDE: Change check for manage access from :edit to :destroy - if current_ability.can?(:destroy, solr_document) - return I18n.t('hyrax.dashboard.my.collection_list.managed_access.manage') - end + return I18n.t('hyrax.dashboard.my.collection_list.managed_access.manage') if current_ability.can?(:destroy, solr_document) # OVERRIDE: Add label for Edit access - if current_ability.can?(:edit, solr_document) - return I18n.t('hyrax.dashboard.my.collection_list.managed_access.edit') - end - if current_ability.can?(:deposit, solr_document) - return I18n.t('hyrax.dashboard.my.collection_list.managed_access.deposit') - end - if current_ability.can?(:read, solr_document) - return I18n.t('hyrax.dashboard.my.collection_list.managed_access.view') - end + return I18n.t('hyrax.dashboard.my.collection_list.managed_access.edit') if current_ability.can?(:edit, solr_document) + return I18n.t('hyrax.dashboard.my.collection_list.managed_access.deposit') if current_ability.can?(:deposit, solr_document) + return I18n.t('hyrax.dashboard.my.collection_list.managed_access.view') if current_ability.can?(:read, solr_document) '' end @@ -87,7 +79,7 @@ def banner_file filename = File.split(banner_info.first.local_path).last unless banner_info.empty? alttext = banner_info.first.alt_text unless banner_info.empty? relative_path = "/" + banner_info.first.local_path.split("/")[-4..-1].join("/") unless banner_info.empty? - { filename: filename, relative_path: relative_path, alt_text: alttext } + { filename:, relative_path:, alt_text: alttext } end end @@ -106,9 +98,7 @@ def display_unfeature_collection_link? def collection_featured? # only look this up if it's not boolean; ||= won't work here - if @collection_featured.nil? - @collection_featured = FeaturedCollection.where(collection_id: solr_document.id).exists? - end + @collection_featured = FeaturedCollection.where(collection_id: solr_document.id).exists? if @collection_featured.nil? @collection_featured end diff --git a/app/presenters/hyrax/homepage_presenter.rb b/app/presenters/hyrax/homepage_presenter.rb deleted file mode 100644 index 76fe4bf49..000000000 --- a/app/presenters/hyrax/homepage_presenter.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax 3.4.0 to add methods to: -# hide featured researcher -# hide featured works -# hide recently uploaded -# hide share button -module Hyrax - class HomepagePresenter - class_attribute :create_work_presenter_class - self.create_work_presenter_class = Hyrax::SelectTypeListPresenter - attr_reader :current_ability, :collections - - def initialize(current_ability, collections) - @current_ability = current_ability - @collections = collections - end - - # OVERRIDE: Hyrax v3.4.0 to removed: @return [Boolean] If the - # display_share_button_when_not_logged_in? is activated, then - # return true since we are utilizing the feature flipper - # Flipflop.show_share_button? in Hyku. - - # @return [Boolean] If the current user is a guest - # and the feature flipper is enabled or if the signed in - # user has permission to create at least one kind of work - # and the feature flipper is enabled. - - def display_share_button? - Flipflop.show_share_button? && current_ability.can_create_any_work? || - Flipflop.show_share_button? && user_unregistered? - end - - # A presenter for selecting a work type to create - # this is needed here because the selector is in the header on every page - def create_work_presenter - @create_work_presenter ||= create_work_presenter_class.new(current_ability.current_user) - end - - def create_many_work_types? - create_work_presenter.many? - end - - def draw_select_work_modal? - display_share_button? && create_many_work_types? - end - - def first_work_type - create_work_presenter.first_model - end - - # changed to add feature flag for featured researcher - def display_featured_researcher? - Flipflop.show_featured_researcher? - end - - # changed to add feature flag for featured work - def display_featured_works? - Flipflop.show_featured_works? - end - - # changed to add feature flag for recently uploaded - def display_recently_uploaded? - Flipflop.show_recently_uploaded? - end - - private - - def user_unregistered? - current_ability.current_user.new_record? || - current_ability.current_user.guest? - end - end -end diff --git a/app/presenters/hyrax/homepage_presenter_decorator.rb b/app/presenters/hyrax/homepage_presenter_decorator.rb new file mode 100644 index 000000000..15b52204e --- /dev/null +++ b/app/presenters/hyrax/homepage_presenter_decorator.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# OVERRIDE Hyrax 5.0 to hide features via flipper +# hide featured researcher +# hide featured works +# hide recently uploaded +# hide share button +module Hyrax + module HomepagePresenterDecorator + def display_share_button? + Flipflop.show_share_button? && current_ability.can_create_any_work? || + Flipflop.show_share_button? && user_unregistered? + end + + def display_featured_researcher? + Flipflop.show_featured_researcher? + end + + def display_featured_works? + Flipflop.show_featured_works? + end + + def display_recently_uploaded? + Flipflop.show_recently_uploaded? + end + end +end + +Hyrax::HomepagePresenter.prepend(Hyrax::HomepagePresenterDecorator) diff --git a/app/presenters/hyrax/iiif_manifest_presenter_decorator.rb b/app/presenters/hyrax/iiif_manifest_presenter_decorator.rb index c34dbb167..faf5729f1 100644 --- a/app/presenters/hyrax/iiif_manifest_presenter_decorator.rb +++ b/app/presenters/hyrax/iiif_manifest_presenter_decorator.rb @@ -30,7 +30,7 @@ def manifest_url return '' if id.blank? protocol = Site.account.ssl_configured ? 'https' : 'http' - Rails.application.routes.url_helpers.polymorphic_url([:manifest, model], host: hostname, protocol: protocol) + Rails.application.routes.url_helpers.polymorphic_url([:manifest, model], host: hostname, protocol:) end def iiif_version diff --git a/app/services/create_account.rb b/app/services/create_account.rb index f021fbff4..536c2f595 100644 --- a/app/services/create_account.rb +++ b/app/services/create_account.rb @@ -46,18 +46,18 @@ def create_defaults Hyrax::CollectionType.find_or_create_admin_set_type return if account.search_only? - AdminSet.find_or_create_default_admin_set_id + Hyrax::AdminSetCreateService.find_or_create_default_admin_set.id end # Workaround for upstream issue https://github.com/samvera/hyrax/issues/3136 def fillin_translations collection_types = Hyrax::CollectionType.all collection_types.each do |c| - next unless c.title =~ /^translation missing/ + next unless /^translation missing/.match?(c.title) oldtitle = c.title c.title = I18n.t(c.title.gsub("translation missing: en.", '')) c.save - Rails.logger.debug "#{oldtitle} changed to #{c.title}" + Rails.logger.debug { "#{oldtitle} changed to #{c.title}" } end end @@ -87,7 +87,7 @@ def schedule_recurring_jobs private - def initialize_account_data - Site.update(account: account) - end + def initialize_account_data + Site.update(account:) + end end diff --git a/app/services/group_aware_role_checker.rb b/app/services/group_aware_role_checker.rb index 76b7752bc..d366e46a8 100644 --- a/app/services/group_aware_role_checker.rb +++ b/app/services/group_aware_role_checker.rb @@ -12,16 +12,16 @@ module GroupAwareRoleChecker private - # Check for the presence of the passed role_name in the User's Roles and - # the User's Hyrax::Group's Roles. - def has_group_aware_role?(role_name) # rubocop:disable Naming/PredicateName - return false if current_user.new_record? - return true if current_user.has_role?(role_name, Site.instance) + # Check for the presence of the passed role_name in the User's Roles and + # the User's Hyrax::Group's Roles. + def has_group_aware_role?(role_name) # rubocop:disable Naming/PredicateName + return false if current_user.new_record? + return true if current_user.has_role?(role_name, Site.instance) - current_user.hyrax_groups.each do |group| - return true if group.has_site_role?(role_name) - end - - false + current_user.hyrax_groups.each do |group| + return true if group.has_site_role?(role_name) end + + false + end end diff --git a/app/services/hyrax/admin_set_create_service_decorator.rb b/app/services/hyrax/admin_set_create_service_decorator.rb index 631681a0c..8670b22eb 100644 --- a/app/services/hyrax/admin_set_create_service_decorator.rb +++ b/app/services/hyrax/admin_set_create_service_decorator.rb @@ -16,8 +16,8 @@ def create! ActiveRecord::Base.transaction do permission_template = PermissionTemplate.find_by(source_id: result.id.to_s) || permissions_create_service.create_default(collection: result, - creating_user: creating_user) - create_workflows_for(permission_template: permission_template) + creating_user:) + create_workflows_for(permission_template:) # OVERRIDE: Remove call to #create_default_access_for, which granted # deposit access to all registered users for the Default Admin Set end @@ -38,12 +38,12 @@ def workflow_agents end def create_workflows_for(permission_template:) - workflow_importer.call(permission_template: permission_template) + workflow_importer.call(permission_template:) # OVERRIDE: Extract and expand upon granting Workflow Roles into service object so it can be used in RolesService Hyrax::Workflow::PermissionGrantor - .grant_default_workflow_roles!(permission_template: permission_template, creating_user: creating_user) + .grant_default_workflow_roles!(permission_template:, creating_user:) Sipity::Workflow - .activate!(permission_template: permission_template, workflow_name: Hyrax.config.default_active_workflow_name) + .activate!(permission_template:, workflow_name: Hyrax.config.default_active_workflow_name) end end end diff --git a/app/services/hyrax/collection_types/create_service.rb b/app/services/hyrax/collection_types/create_service.rb index 07891f9b3..38950d7df 100644 --- a/app/services/hyrax/collection_types/create_service.rb +++ b/app/services/hyrax/collection_types/create_service.rb @@ -167,7 +167,7 @@ class CreateService # rubocop:disable Metrics/ClassLength # @return [Hyrax::CollectionType] the newly created collection type instance def self.create_collection_type(machine_id:, title:, options: {}) opts = DEFAULT_OPTIONS.merge(options).except(:participants) - ct = Hyrax::CollectionType.create!(opts.merge(machine_id: machine_id, title: title)) + ct = Hyrax::CollectionType.create!(opts.merge(machine_id:, title:)) participants = options[:participants].presence || DEFAULT_OPTIONS[:participants] add_participants(ct.id, participants) ct @@ -208,6 +208,7 @@ def self.create_user_collection_type # The same values can be retrieved directly from a passed in ability. # If calling from Abilities, pass the ability. # If you try to get the ability from the user, you end up in an infinite loop. + # rubocop:disable Metrics/MethodLength def self.add_default_participants(collection_type_id) return unless collection_type_id default_participants = [{ agent_type: Hyrax::CollectionTypeParticipant::GROUP_TYPE, @@ -233,6 +234,7 @@ def self.add_default_participants(collection_type_id) end add_participants(collection_type_id, default_participants) end + # rubocop:enable Metrics/MethodLength ## # @api public diff --git a/app/services/hyrax/collections/permissions_create_service_decorator.rb b/app/services/hyrax/collections/permissions_create_service_decorator.rb index 9324f41e7..3f6606761 100644 --- a/app/services/hyrax/collections/permissions_create_service_decorator.rb +++ b/app/services/hyrax/collections/permissions_create_service_decorator.rb @@ -58,9 +58,11 @@ def access_grants_attributes(collection_type:, creating_user:, grants:) access: Hyrax::PermissionTemplateAccess::VIEW } end + # rubocop:disable Lint/Void attribute_list + # rubocop:enable Lint/Void # OVERRIDE END - end + managers_of_collection_type(collection_type: collection_type) + grants + end + managers_of_collection_type(collection_type:) + grants end private :access_grants_attributes end diff --git a/app/services/hyrax/collections/permissions_service_decorator.rb b/app/services/hyrax/collections/permissions_service_decorator.rb index 7a021dd2f..60a29773e 100644 --- a/app/services/hyrax/collections/permissions_service_decorator.rb +++ b/app/services/hyrax/collections/permissions_service_decorator.rb @@ -12,7 +12,7 @@ module PermissionsServiceDecorator # to have a whole method JUST for that... maybe make #manage_access_to_collection # public or use #send to call the private method directly? def can_manage_collection?(collection_id:, ability:) - manage_access_to_collection?(collection_id: collection_id, ability: ability) + manage_access_to_collection?(collection_id:, ability:) end end end diff --git a/app/services/hyrax/manifest_builder_service_decorator.rb b/app/services/hyrax/manifest_builder_service_decorator.rb index 218420566..fdfe796ab 100644 --- a/app/services/hyrax/manifest_builder_service_decorator.rb +++ b/app/services/hyrax/manifest_builder_service_decorator.rb @@ -4,22 +4,22 @@ module Hyrax module ManifestBuilderServiceDecorator private - ## - # @return [Hash<Array>] the Hash to be used by "label" to change `&` to `&` - # @see #loof - def sanitize_value(text) - return loof(text) unless text.is_a?(Hash) - text[text.keys.first] = text.values.flatten.map { |value| loof(value) } - text - end + ## + # @return [Hash<Array>] the Hash to be used by "label" to change `&` to `&` + # @see #loof + def sanitize_value(text) + return loof(text) unless text.is_a?(Hash) + text[text.keys.first] = text.values.flatten.map { |value| loof(value) } + text + end - ## - # @return [String] the String that gets unescaped since Loofah is too aggressive for example - # it changes to `&` to `&` which will be displayed in the Universal Viewer and manifest - # @see #sanitize_value - def loof(text) - CGI.unescapeHTML(Loofah.fragment(text.to_s).scrub!(:prune).to_s) - end + ## + # @return [String] the String that gets unescaped since Loofah is too aggressive for example + # it changes to `&` to `&` which will be displayed in the Universal Viewer and manifest + # @see #sanitize_value + def loof(text) + CGI.unescapeHTML(Loofah.fragment(text.to_s).scrub!(:prune).to_s) + end end end diff --git a/app/services/hyrax/thumbnail_path_service.rb b/app/services/hyrax/thumbnail_path_service.rb index cccadc9a5..af3851f72 100644 --- a/app/services/hyrax/thumbnail_path_service.rb +++ b/app/services/hyrax/thumbnail_path_service.rb @@ -18,54 +18,54 @@ def call(object) private - def return_path(thumb) - if audio?(thumb) - audio_image - elsif thumbnail?(thumb) - thumbnail_path(thumb) - else - default_image - end + def return_path(thumb) + if audio?(thumb) + audio_image + elsif thumbnail?(thumb) + thumbnail_path(thumb) + else + default_image end + end - def audio?(thumb) - service = thumb.respond_to?(:audio?) ? thumb : Hyrax::FileSetTypeService.new(file_set: thumb) - service.audio? - end + def audio?(thumb) + service = thumb.respond_to?(:audio?) ? thumb : Hyrax::FileSetTypeService.new(file_set: thumb) + service.audio? + end - def fetch_thumbnail(object) - return object if object.thumbnail_id == object.id - Hyrax.query_service.find_by(id: object.thumbnail_id) - rescue Valkyrie::Persistence::ObjectNotFoundError, Hyrax::ObjectNotFoundError - Rails.logger.error("Couldn't find thumbnail #{object.thumbnail_id} for #{object.id}") - nil - end + def fetch_thumbnail(object) + return object if object.thumbnail_id == object.id + Hyrax.query_service.find_by(id: object.thumbnail_id) + rescue Valkyrie::Persistence::ObjectNotFoundError, Hyrax::ObjectNotFoundError + Rails.logger.error("Couldn't find thumbnail #{object.thumbnail_id} for #{object.id}") + nil + end - # @return the network path to the thumbnail - # @param [FileSet] thumbnail the object that is the thumbnail - def thumbnail_path(thumbnail) - Hyrax::Engine.routes.url_helpers.download_path(thumbnail.id, - file: 'thumbnail') - end + # @return the network path to the thumbnail + # @param [FileSet] thumbnail the object that is the thumbnail + def thumbnail_path(thumbnail) + Hyrax::Engine.routes.url_helpers.download_path(thumbnail.id, + file: 'thumbnail') + end - def default_image - Site.instance.default_work_image&.url || ActionController::Base.helpers.image_path('default.png') - end + def default_image + Site.instance.default_work_image&.url || ActionController::Base.helpers.image_path('default.png') + end - def audio_image - ActionController::Base.helpers.image_path 'audio.png' - end + def audio_image + ActionController::Base.helpers.image_path 'audio.png' + end - # @return true if there a file on disk for this object, otherwise false - # @param [FileSet] thumb - the object that is the thumbnail - def thumbnail?(thumb) - File.exist?(thumbnail_filepath(thumb)) - end + # @return true if there a file on disk for this object, otherwise false + # @param [FileSet] thumb - the object that is the thumbnail + def thumbnail?(thumb) + File.exist?(thumbnail_filepath(thumb)) + end - # @param [FileSet] thumb - the object that is the thumbnail - def thumbnail_filepath(thumb) - Hyrax::DerivativePath.derivative_path_for_reference(thumb, 'thumbnail') - end + # @param [FileSet] thumb - the object that is the thumbnail + def thumbnail_filepath(thumb) + Hyrax::DerivativePath.derivative_path_for_reference(thumb, 'thumbnail') + end end end end diff --git a/app/services/hyrax/workflow/permission_grantor.rb b/app/services/hyrax/workflow/permission_grantor.rb index ed93c054a..91bb2c362 100644 --- a/app/services/hyrax/workflow/permission_grantor.rb +++ b/app/services/hyrax/workflow/permission_grantor.rb @@ -12,7 +12,7 @@ module Workflow # @see RolesService class PermissionGrantor def self.grant_default_workflow_roles!(permission_template:, creating_user: nil) - new(permission_template: permission_template, creating_user: creating_user).call + new(permission_template:, creating_user:).call end attr_accessor :permission_template, :creating_user @@ -36,64 +36,64 @@ def call private - # Force creation of registered roles if they don't exist - def register_default_sipity_roles! - Sipity::Role[Hyrax::RoleRegistry::MANAGING] - Sipity::Role[Hyrax::RoleRegistry::APPROVING] - Sipity::Role[Hyrax::RoleRegistry::DEPOSITING] - end + # Force creation of registered roles if they don't exist + def register_default_sipity_roles! + Sipity::Role[Hyrax::RoleRegistry::MANAGING] + Sipity::Role[Hyrax::RoleRegistry::APPROVING] + Sipity::Role[Hyrax::RoleRegistry::DEPOSITING] + end - def grant_all_workflow_roles_to_creating_user_and_admins! - # The admin group should always receive workflow roles - workflow_agents = [Hyrax::Group.find_by!(name: ::Ability.admin_group_name)] - # The default admin set does not have a creating user - workflow_agents << creating_user if creating_user - workflow_agents |= Hyrax::Group.select { |g| g.has_site_role?(:admin) }.tap do |agent_list| - ::User.find_each do |u| - agent_list << u if u.has_role?(:admin, Site.instance) - end + def grant_all_workflow_roles_to_creating_user_and_admins! + # The admin group should always receive workflow roles + workflow_agents = [Hyrax::Group.find_by!(name: ::Ability.admin_group_name)] + # The default admin set does not have a creating user + workflow_agents << creating_user if creating_user + workflow_agents |= Hyrax::Group.select { |g| g.has_site_role?(:admin) }.tap do |agent_list| + ::User.find_each do |u| + agent_list << u if u.has_role?(:admin, Site.instance) end - - grant_workflow_roles!(workflow_agents: workflow_agents, role_filters: nil) end - def grant_workflow_roles_to_editors! - editor_sipity_roles = [Hyrax::RoleRegistry::APPROVING, Hyrax::RoleRegistry::DEPOSITING] - workflow_agents = Hyrax::Group.select { |g| g.has_site_role?(:work_editor) }.tap do |agent_list| - ::User.find_each do |u| - agent_list << u if u.has_role?(:work_editor, Site.instance) - end - end + grant_workflow_roles!(workflow_agents:, role_filters: nil) + end - grant_workflow_roles!(workflow_agents: workflow_agents, role_filters: editor_sipity_roles) + def grant_workflow_roles_to_editors! + editor_sipity_roles = [Hyrax::RoleRegistry::APPROVING, Hyrax::RoleRegistry::DEPOSITING] + workflow_agents = Hyrax::Group.select { |g| g.has_site_role?(:work_editor) }.tap do |agent_list| + ::User.find_each do |u| + agent_list << u if u.has_role?(:work_editor, Site.instance) + end end - def grant_workflow_roles_to_depositors! - depositor_sipity_role = [Hyrax::RoleRegistry::DEPOSITING] - workflow_agents = Hyrax::Group.select { |g| g.has_site_role?(:work_depositor) }.tap do |agent_list| - ::User.find_each do |u| - agent_list << u if u.has_role?(:work_depositor, Site.instance) - end - end + grant_workflow_roles!(workflow_agents:, role_filters: editor_sipity_roles) + end - grant_workflow_roles!(workflow_agents: workflow_agents, role_filters: depositor_sipity_role) + def grant_workflow_roles_to_depositors! + depositor_sipity_role = [Hyrax::RoleRegistry::DEPOSITING] + workflow_agents = Hyrax::Group.select { |g| g.has_site_role?(:work_depositor) }.tap do |agent_list| + ::User.find_each do |u| + agent_list << u if u.has_role?(:work_depositor, Site.instance) + end end - def grant_workflow_roles!(workflow_agents:, role_filters:) - role_set = if role_filters.present? - Sipity::Role.select { |role| role_filters.include?(role.name) } - else - Sipity::Role.all - end + grant_workflow_roles!(workflow_agents:, role_filters: depositor_sipity_role) + end + + def grant_workflow_roles!(workflow_agents:, role_filters:) + role_set = if role_filters.present? + Sipity::Role.select { |role| role_filters.include?(role.name) } + else + Sipity::Role.all + end - permission_template.available_workflows.each do |workflow| - role_set.each do |role| - Hyrax::Workflow::PermissionGenerator.call(roles: role, - workflow: workflow, - agents: workflow_agents) - end + permission_template.available_workflows.each do |workflow| + role_set.each do |role| + Hyrax::Workflow::PermissionGenerator.call(roles: role, + workflow:, + agents: workflow_agents) end end + end end end end diff --git a/app/services/hyrax/workflow/permission_query.rb b/app/services/hyrax/workflow/permission_query.rb deleted file mode 100644 index 8ac3f2ecd..000000000 --- a/app/services/hyrax/workflow/permission_query.rb +++ /dev/null @@ -1,450 +0,0 @@ -# frozen_string_literal: true - -# OVERRIDE Hyrax v3.4.2 Expand functionality for Groups with Roles Feature -# @see https://github.com/samvera/hyku/wiki/Groups-with-Roles-Feature -# rubocop:disable Metrics/ModuleLength -module Hyrax - module Workflow - # Welcome intrepid developer. You have stumbled into some complex data - # interactions. There are a lot of data collaborators regarding these tests. - # I would love this to be more in isolation, but that is not in the cards as - # there are at least 16 database tables interacting to ultimately answer the - # following question: - # - # * What actions can a given user take on an entity? - # - # Could there be more efficient queries? Yes. However, the composition of - # queries has proven to be a very powerful means of understanding and - # exploring the problem. - # - # @note There is an indication of public or private api. The intent of this - # is to differentiate what are methods that are the primary entry points - # as understood as of the commit that has the @api tag. However, these are - # public methods because they have been tested in isolation and are used - # to help compose the `@api public` methods. - # - # @todo Refactor the large ABC methods in this module. - module PermissionQuery - module_function - - def entity_responsibilities - @entity_responsibilities ||= Sipity::EntitySpecificResponsibility.arel_table - end - - def workflow_responsibilities - @workflow_responsibilities ||= Sipity::WorkflowResponsibility.arel_table - end - - def workflow_roles - @workflow_roles ||= Sipity::WorkflowRole.arel_table - end - - # @api public - # - # For the given :user and :entity return only workflow actions that meet all of the following: - # - # * available for the :entity's workflow state - # * permitted to be taken by one or more roles in which the user is assigned - # either at the workflow level or the entity level. - # - # * Actions to which the user Only actions permitted to the user - # - # @param user [User] - # @param entity [Object] an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowAction>] - def scope_permitted_workflow_actions_available_for_current_state(user:, entity:) - workflow_actions_scope = scope_workflow_actions_available_for_current_state(entity: entity) - workflow_state_actions_scope = scope_permitted_entity_workflow_state_actions(user: user, entity: entity) - workflow_actions_scope.where( - workflow_actions_scope.arel_table[:id].in( - workflow_state_actions_scope.arel_table.project( - workflow_state_actions_scope.arel_table[:workflow_action_id] - ).where(workflow_state_actions_scope.arel.constraints.reduce) - ) - ) - end - - # @api public - # - # Agents associated with the given :entity and how they are associated - # with the given. - # - # @param entity [Object] that can be converted into a Sipity::Entity - # @param role [Object] that can be converted into a Sipity::Role - # @return [ActiveRecord::Relation<Sipity::Agent>] augmented with - # - def scope_agents_associated_with_entity_and_role(entity:, role:) # rubocop:disable Metrics/AbcSize - entity = Sipity::Entity(entity) - role = Sipity::Role(role) - - agents = Sipity::Agent.arel_table - - agents_select_manager = agents.project( - :*, - Arel.sql("'#{Sipity::Agent::ENTITY_LEVEL_AGENT_RELATIONSHIP}'").as('agent_processing_relationship') - ).where( - agents[:id].in( - entity_responsibilities.project(entity_responsibilities[:agent_id]).join(workflow_roles).on( - workflow_roles[:id].eq(entity_responsibilities[:workflow_role_id]) - ).where( - entity_responsibilities[:entity_id].eq(entity.id).and( - workflow_roles[:role_id].eq(role.id) - ) - ) - ) - ).union( - agents.project( - :*, - Arel.sql("'#{Sipity::Agent::WORKFLOW_LEVEL_AGENT_RELATIONSHIP}'").as('agent_processing_relationship') - ).where( - agents[:id].in( - workflow_responsibilities.project(workflow_responsibilities[:agent_id]).join(workflow_roles).on( - workflow_roles[:id].eq(workflow_responsibilities[:workflow_role_id]) - ).where( - workflow_roles[:workflow_id].eq(entity.workflow_id).and( - workflow_roles[:role_id].eq(role.id) - ) - ) - ) - ) - ) - # I would love to use the following: - # `Agent.find_by_sql(agents_select_manager.to_sql)` - # - # However AREL is adding an opening and closing parenthesis to the query - # statement. So I needed to massage that output, as follows: - # - # ```ruby - # Agent.find_by_sql( - # agents_select_manager.to_sql.sub(/\A\s*\(\s*(.*)\s*\)\s*\Z/,'\1') - # ) - # ``` - # - # Instead I'm taking an example from: - # https://github.com/danshultz/mastering_active_record_sample_code/blob/a656c60ca7a2e27b5cd1aadbdf3bdc1814c37000/app/models/beer.rb#L77-L81 - # - # Note, I'm making a dynamic query with a result the same as the table - # name of the model that I'm using. - Sipity::Agent.from(agents.create_table_alias(agents_select_manager, agents.table_name)).all - end - # rubocop:enable Metrics/AbcSize, Metrics/MethodLength - - # @api public - # - # Roles associated with the given :entity - # @param entity [Object] that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::Role>] - def scope_roles_associated_with_the_given_entity(entity:) - entity = Sipity::Entity(entity) - return Sipity::Role.none unless entity - Sipity::Role.where( - Sipity::Role.arel_table[:id].in( - workflow_roles.project(workflow_roles[:role_id]).where( - workflow_roles[:workflow_id].eq(entity.workflow_id) - ) - ) - ) - end - - # @api public - # - # Is the user authorized to take the processing action on the given - # entity? - # - # @param user [User] - # @param entity an object that can be converted into a Sipity::Entity - # @param action an object that can be converted into a Sipity::WorkflowAction#name - # @return [Boolean] - def authorized_for_processing?(user:, entity:, action:) - action_name = Sipity::WorkflowAction.name_for(action) - scope_permitted_workflow_actions_available_for_current_state(user: user, entity: entity) - .find_by(Sipity::WorkflowAction.arel_table[:name].eq(action_name)).present? - end - - # @api public - # - # An ActiveRecord::Relation scope that meets the following criteria: - # - # * All of the Processing Agents directly associated with the given :user - # - # @param user [User] - # @return [ActiveRecord::Relation<Sipity::Agent>] - def scope_processing_agents_for(user:) - return Sipity::Agent.none if user.blank? - return Sipity::Agent.none unless user.persisted? - user_agent = Sipity::Agent(user) - group_agents = user.groups.map do |g| - Sipity::Agent(Hyrax::Group.new(name: g)) - end - Sipity::Agent.where(id: group_agents + [user_agent]) - end - - PermissionScope = Struct.new(:entity, :workflow) - private_constant :PermissionScope - - # @api public - # - # An ActiveRecord::Relation scope that meets the following criteria: - # - # * Sipity::Entity in a state in which I have access to based on: - # - The entity specific responsibility - # - For which I've been assigned a role - # - The workflow specific responsibility - # - For which I've been assigned a role - # - # @param [User] user - # - # @return [ActiveRecord::Relation<Sipity::Entity>] - # - def scope_entities_for_the_user(user:) # rubocop:disable Metrics/AbcSize - entities = Sipity::Entity.arel_table - workflow_state_actions = Sipity::WorkflowStateAction.arel_table - workflow_states = Sipity::WorkflowState.arel_table - workflow_state_action_permissions = Sipity::WorkflowStateActionPermission.arel_table - - user_agent_scope = scope_processing_agents_for(user: user) - user_agent_contraints = user_agent_scope.arel_table.project( - user_agent_scope.arel_table[:id] - ).where(user_agent_scope.arel.constraints) - - join_builder = lambda do |responsibility| - entities.project( - entities[:id] - ).join(workflow_state_actions).on( - workflow_state_actions[:originating_workflow_state_id].eq(entities[:workflow_state_id]) - ).join(workflow_state_action_permissions).on( - workflow_state_action_permissions[:workflow_state_action_id].eq(workflow_state_actions[:id]) - ).join(workflow_states).on( - workflow_states[:id].eq(workflow_state_actions[:originating_workflow_state_id]) - ).join(responsibility).on( - responsibility[:workflow_role_id].eq(workflow_state_action_permissions[:workflow_role_id]) - ) - end - - where_builder = ->(responsibility) { responsibility[:agent_id].in(user_agent_contraints) } - - entity_specific_joins = join_builder.call(entity_responsibilities) - workflow_specific_joins = join_builder.call(workflow_responsibilities) - - entity_specific_where = where_builder.call(entity_responsibilities).and( - entities[:id].eq(entity_responsibilities[:entity_id]) - ) - workflow_specific_where = where_builder.call(workflow_responsibilities) - - Sipity::Entity.where( - entities[:id].in(entity_specific_joins.where(entity_specific_where)) - .or(entities[:id].in(workflow_specific_joins.where(workflow_specific_where))) - ) - end - # rubocop:enable Metrics/AbcSize, Metrics/MethodLength - - # @api public - # - # An ActiveRecord::Relation scope that meets the following criteria: - # - # * Users that are directly associated with the given entity through one or - # more of the given roles within the entity's workflow - # * Users that are indirectly associated with the given entity by group - # and role. - # - # @param roles [Sipity::Role] - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<User>] - # - def scope_users_for_entity_and_roles(entity:, roles:) # rubocop:disable Metrics/AbcSize - entity = Sipity::Entity(entity) - role_ids = Array.wrap(roles).map { |role| Sipity::Role(role).id } - user_polymorphic_type = ::User.base_class - - user_table = ::User.arel_table - agent_table = Sipity::Agent.arel_table - - workflow_role_id_subquery = workflow_roles.project(workflow_roles[:id]).where( - workflow_roles[:workflow_id].eq(entity.workflow_id).and(workflow_roles[:role_id].in(role_ids)) - ) - - workflow_agent_id_subquery = workflow_responsibilities.project(workflow_responsibilities[:agent_id]).where( - workflow_responsibilities[:workflow_role_id].in(workflow_role_id_subquery) - ) - - entity_agent_id_subquery = entity_responsibilities.project(entity_responsibilities[:agent_id]).where( - entity_responsibilities[:workflow_role_id].in(workflow_role_id_subquery) - .and(entity_responsibilities[:entity_id].eq(entity.id)) - ) - - # Default to "integer" for adapters like Postgres and Sqlite, but cast - # to "signed" for Mysql. The type CAST causes a SQL syntax error for an - # unsupported type depending on which adapter is being used. - type = ActiveRecord::Base.connection.adapter_name.casecmp("mysql2").zero? ? "signed" : "integer" - cast = Arel::Nodes::NamedFunction.new "CAST", [agent_table[:proxy_for_id].as(type)] - - sub_query_for_user = agent_table.project(cast).where( - agent_table[:id].in(workflow_agent_id_subquery) - .or(agent_table[:id].in(entity_agent_id_subquery)) - ).where( - agent_table[:proxy_for_type].eq(user_polymorphic_type) - ) - - ::User.where(user_table[:id].in(sub_query_for_user)) - end - # rubocop:enable Metrics/AbcSize, Metrics/MethodLength - - def user_emails_for_entity_and_roles(entity:, roles:) - scope_users_for_entity_and_roles(entity: entity, roles: roles).pluck(:email) - end - - # @api public - # - # For the given :user and :entity, return an ActiveRecord::Relation that, - # if resolved, will be all of the assocated workflow roles for both the - # workflow responsibilities and the entity specific responsibilities. - # - # @param user [User] - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowRole>] - def scope_processing_workflow_roles_for_user_and_entity(user:, entity:) - entity = Sipity::Entity(entity) - workflow_scope = scope_processing_workflow_roles_for_user_and_workflow(user: user, workflow: entity.workflow) - - entity_specific_scope = scope_processing_workflow_roles_for_user_and_entity_specific(user: user, entity: entity) - Sipity::WorkflowRole.where( - workflow_scope.arel.constraints.reduce.or(entity_specific_scope.arel.constraints.reduce) - ) - end - - # @api private - # - # For the given :user and :workflow, return an ActiveRecord::Relation that, - # if resolved, will be all of the assocated workflow roles that are - # assigned to directly to the workflow. - # - # @param user [User] - # @param workflow [Sipity::Workflow] - # @return [ActiveRecord::Relation<Sipity::WorkflowRole>] - def scope_processing_workflow_roles_for_user_and_workflow(user:, workflow:) - agent_constraints = scope_processing_agents_for(user: user) - workflow_role_subquery = workflow_roles[:id].in( - workflow_responsibilities.project(workflow_responsibilities[:workflow_role_id]) - .where( - workflow_responsibilities[:agent_id].in( - agent_constraints.arel_table.project( - agent_constraints.arel_table[:id] - ).where(agent_constraints.arel.constraints) - ) - ) - ) - Sipity::WorkflowRole.where( - workflow_roles[:workflow_id].eq(workflow.id).and(workflow_role_subquery) - ) - end - - # @api private - # - # For the given :user and :entity, return an ActiveRecord::Relation that, - # if resolved, will be all of the assocated workflow roles that are - # assigned to specifically to the entity (and not the parent workflow). - # - # @param user [User] - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowRole>] - def scope_processing_workflow_roles_for_user_and_entity_specific(user:, entity:) - entity = Sipity::Entity(entity) - agent_scope = scope_processing_agents_for(user: user) - - Sipity::WorkflowRole.where( - workflow_roles[:id].in( - entity_responsibilities.project(entity_responsibilities[:workflow_role_id]) - .where( - entity_responsibilities[:agent_id].in( - agent_scope.arel_table.project( - agent_scope.arel_table[:id] - ).where( - agent_scope.arel.constraints.reduce.and(entity_responsibilities[:entity_id].eq(entity.id)) - ) - ) - ) - ) - ) - end - - # @api private - # - # For the given :user and :entity, return an ActiveRecord::Relation, - # that if resolved, will be collection of - # Sipity::WorkflowStateAction object to which the user has - # permission to do something. - # - # An ActiveRecord::Relation scope that meets the following criteria: - # - # * The actions are available for the given entity's current state - # * The actions are available for the given user based on their role. - # Either: - # - Directly via an agent associated with a user - # - Indirectly via an agent associated with a group - # - # @param user [User] - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowStateAction>] - # - def scope_permitted_entity_workflow_state_actions(user:, entity:) - entity = Sipity::Entity(entity) - workflow_state_actions = Sipity::WorkflowStateAction - permissions = Sipity::WorkflowStateActionPermission - role_scope = scope_processing_workflow_roles_for_user_and_entity(user: user, entity: entity) - - workflow_state_actions.where( - workflow_state_actions.arel_table[:originating_workflow_state_id].eq(entity.workflow_state_id).and( - workflow_state_actions.arel_table[:id].in( - permissions.arel_table.project( - permissions.arel_table[:workflow_state_action_id] - ).where( - permissions.arel_table[:workflow_role_id].in( - role_scope.arel_table.project(role_scope.arel_table[:id]).where( - role_scope.arel.constraints.reduce - ) - ) - ) - ) - ) - ) - end - - # @api public - # - # For the given :entity return an ActiveRecord::Relation that when - # resolved will be only the workflow actions that: - # - # * Are available for the entity's workflow_state - # - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowAction>] - def scope_workflow_actions_for_current_state(entity:) - entity = Sipity::Entity(entity) - state_actions_table = Sipity::WorkflowStateAction.arel_table - Sipity::WorkflowAction.where( - Sipity::WorkflowAction.arel_table[:id].in( - state_actions_table.project(state_actions_table[:workflow_action_id]) - .where(state_actions_table[:originating_workflow_state_id].eq(entity.workflow_state_id)) - ) - ) - end - - # @api private - # - # For the given :entity, return an ActiveRecord::Relation, that - # if resolved, that lists all of the actions available for the entity and - # its current state. - # - # * All actions that are associated with actions that do not have prerequsites - # * All actions that have prerequisites and all of those prerequisites are complete - # - # @param entity an object that can be converted into a Sipity::Entity - # @return [ActiveRecord::Relation<Sipity::WorkflowAction>] - def scope_workflow_actions_available_for_current_state(entity:) - workflow_actions_for_current_state = scope_workflow_actions_for_current_state(entity: entity) - Sipity::WorkflowAction.where(workflow_actions_for_current_state.arel.constraints.reduce) - end - end - end -end -# rubocop:enable Metrics/ModuleLength diff --git a/app/services/roles_service.rb b/app/services/roles_service.rb index c5c6a5de8..3d4b57f67 100644 --- a/app/services/roles_service.rb +++ b/app/services/roles_service.rb @@ -71,15 +71,13 @@ def create_default_roles! return '`AccountElevator.switch!` into an Account before creating default Roles' if Site.instance.is_a?(NilSite) DEFAULT_ROLES.each do |role_name| - find_or_create_site_role!(role_name: role_name) + find_or_create_site_role!(role_name:) end end def create_default_hyrax_groups_with_roles! # Prevent Hyrax::Groups from being created in the public schema - if Site.instance.is_a?(NilSite) - return '`AccountElevator.switch!` into an Account before creating default Hyrax::Groups' - end + return '`AccountElevator.switch!` into an Account before creating default Hyrax::Groups' if Site.instance.is_a?(NilSite) default_hyrax_groups_with_roles = DEFAULT_HYRAX_GROUPS_WITH_ATTRIBUTES.deep_merge(DEFAULT_ROLES_FOR_DEFAULT_HYRAX_GROUPS) @@ -87,12 +85,12 @@ def create_default_hyrax_groups_with_roles! default_hyrax_groups_with_roles.each do |group_name, group_attrs| group_roles = group_attrs.delete(:roles) group = Hyrax::Group.find_or_create_by!(name: group_name) - group.update_attributes(group_attrs) + group.update(group_attrs) group_roles.each do |role_name| next if role_name.blank? - group.roles |= [find_or_create_site_role!(role_name: role_name)] + group.roles |= [find_or_create_site_role!(role_name:)] end end end @@ -100,6 +98,7 @@ def create_default_hyrax_groups_with_roles! # Because each collection role has some level of access to every Collection within a tenant, # creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups) # means all Collections will show up in Blacklight / Solr queries. + # rubocop:disable Metrics/MethodLength def create_collection_accesses! Collection.find_each do |c| pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: c.id) @@ -129,12 +128,14 @@ def create_collection_accesses! agent_id: 'collection_reader' ) - c.reset_access_controls! if pt.access_grants.count != original_access_grants_count + pt.reset_access_controls_for(collection: c) if pt.access_grants.count != original_access_grants_count end end + # rubocop:enable Metrics/MethodLength # Creating a Hyrax::PermissionTemplateAccess record (combined with Ability#user_groups) # will allow Works in all AdminSets to show up in Blacklight / Solr queries. + # rubocop:disable Metrics/MethodLength def create_admin_set_accesses! AdminSet.find_each do |as| pt = Hyrax::PermissionTemplate.find_or_create_by!(source_id: as.id) @@ -164,9 +165,10 @@ def create_admin_set_accesses! agent_id: 'work_editor' ) - as.reset_access_controls! if pt.access_grants.count != original_access_grants_count + pt.reset_access_controls_for(collection: as) if pt.access_grants.count != original_access_grants_count end end + # rubocop:enable Metrics/MethodLength # Because some of the collection roles have access to every Collection within a tenant, create a # Hyrax::CollectionTypeParticipant record for them on every Hyrax::CollectionType (except the AdminSet) @@ -239,7 +241,7 @@ def prune_stale_guest_users stale_guest_users = User.unscoped.where( 'guest = ? and updated_at < ?', true, - Time.current - 7.days + 7.days.ago ) progress = ProgressBar.create(total: stale_guest_users.count) @@ -249,9 +251,11 @@ def prune_stale_guest_users end end + # rubocop:disable Metrics/MethodLength def seed_superadmin! + # rubocop:disable Rails/UnknownEnv return 'Seed data should not be used in the production environment' if Rails.env.production? || Rails.env.staging? - + # rubocop:enable Rails/UnknownEnv user = User.where(email: 'admin@example.com').first_or_initialize do |u| if u.new_record? u.password = 'testing123' @@ -272,10 +276,13 @@ def seed_superadmin! user end + # rubocop:enable Metrics/MethodLength + # rubocop:disable Metrics/MethodLength def seed_qa_users! + # rubocop:disable Rails/UnknownEnv return 'Seed data should not be used in the production environment' if Rails.env.production? || Rails.env.staging? - + # rubocop:disable Rails/UnknownEnv ActiveRecord::Base.transaction do DEFAULT_ROLES.each do |role_name| user = User.where(email: "#{role_name}@example.com").first_or_initialize do |u| @@ -292,7 +299,7 @@ def seed_qa_users! unless user.has_role?(role_name, Site.instance) user.add_default_group_membership! - user.roles << find_or_create_site_role!(role_name: role_name) + user.roles << find_or_create_site_role!(role_name:) end end @@ -300,5 +307,6 @@ def seed_qa_users! end end end + # rubocop:enable Metrics/MethodLength end end diff --git a/app/services/uploaded_collection_thumbnail_path_service.rb b/app/services/uploaded_collection_thumbnail_path_service.rb index 18a3f662e..3685f9bb9 100644 --- a/app/services/uploaded_collection_thumbnail_path_service.rb +++ b/app/services/uploaded_collection_thumbnail_path_service.rb @@ -7,14 +7,12 @@ def call(object) "/uploads/uploaded_collection_thumbnails/#{object.id}/#{object.id}_card.jpg" end - # rubocop:disable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation def uploaded_thumbnail?(collection) - File.exist?("#{Rails.root.to_s}/public/uploads/uploaded_collection_thumbnails/#{collection.id}/#{collection.id}_card.jpg") + File.exist?(File.join(upload_dir(collection), "#{collection.id}_card.jpg")) end def upload_dir(collection) - "#{Rails.root.to_s}/public/uploads/uploaded_collection_thumbnails/#{collection.id}" + Hyku::Application.path_for("public/uploads/uploaded_collection_thumbnails/#{collection.id}") end - # rubocop:enable Metrics/LineLength, Rails/FilePath, Lint/StringConversionInInterpolation end end diff --git a/app/views/_admin_util_links.html.erb b/app/views/_admin_util_links.html.erb index 808e1230e..86a76ae03 100644 --- a/app/views/_admin_util_links.html.erb +++ b/app/views/_admin_util_links.html.erb @@ -1,22 +1,24 @@ <% if user_signed_in? %> <% if can? :manage, Account %> - <ul class="nav navbar-nav"> - <li> - <%= link_to main_app.proprietor_accounts_path do %> + <ul class="navbar-nav mr-auto"> + <li class="nav-item"> + <%= link_to main_app.proprietor_accounts_path, class: 'nav-link' do %> <span class="fa fa-gears"></span> <%= t("hyku.proprietor.accounts.nav") %> <% end %> </li> - <li> - <%= link_to main_app.proprietor_users_path do %> + <li class="nav-item"> + <%= link_to main_app.proprietor_users_path, class: 'nav-link' do %> <span class="fa fa-users"></span> <%= t("hyku.proprietor.users.nav") %> <% end %> </li> </ul> <% end %> <% end %> -<ul id="user_utility_links" class="nav navbar-nav navbar-right"> +<ul id="user_utility_links" class="navbar-nav ml-auto"> <%= render 'shared/locale_picker' if available_translations.size > 1 %> <% if user_signed_in? %> - <li><%= link_to t("hyrax.toolbar.profile.logout"), main_app.destroy_user_session_path %></li> + <li class="nav-item"> + <%= link_to t("hyrax.toolbar.profile.logout"), main_app.destroy_user_session_path, class: 'nav-link' %> + </li> <% end %> </ul> diff --git a/app/views/_logo.html.erb b/app/views/_logo.html.erb index 3776707b4..08eca88bd 100644 --- a/app/views/_logo.html.erb +++ b/app/views/_logo.html.erb @@ -1,10 +1,10 @@ - <% if logo_image %> - <a id="logo" href="<%= hyrax.root_path %>" data-no-turbolink="true"> - <span class="glyphicon glyphicon-globe" role="img" aria-label="<%= application_name %>" aria-hidden="true"></span> - <%= image_tag logo_image, alt: block_for(name: 'logo_image_text') %> - </a> - <% else %> - <a id="logo" class="navbar-brand" href="<%= hyrax.root_path %>" data-no-turbolink="true"> - <span class="institution_name"><%= application_name %></span> - </a> - <% end %> +<% if logo_image %> + <a id="logo" href="<%= hyrax.root_path %>" data-no-turbolink="true"> + <i class="fa fa-globe" role="img" aria-label="<%= application_name %>" aria-hidden="true"></i> + <%= image_tag logo_image, alt: block_for(name: 'logo_image_text') %> + </a> +<% else %> + <a id="logo" class="navbar-brand" href="<%= hyrax.root_path %>" data-no-turbolink="true"> + <span class="institution_name"><%= application_name %></span> + </a> +<% end %> diff --git a/app/views/_masthead.html.erb b/app/views/_masthead.html.erb index 7c41b1929..bd3892fb8 100644 --- a/app/views/_masthead.html.erb +++ b/app/views/_masthead.html.erb @@ -1,22 +1,18 @@ -<nav id="masthead" class="navbar navbar-inverse navbar-static-top" role="navigation" aria-label="masthead"> - <div class="container-fluid"> - <!-- Brand and toggle get grouped for better mobile display --> - <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#top-navbar-collapse" aria-expanded="false"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <%= render '/logo' %> - </div> +<%# OVERRIDE Hyrax v5.0.0rc1 to render either admin or user util links %> - <div class="collapse navbar-collapse" id="top-navbar-collapse"> +<header aria-label="header" class="top-header"> + <nav id="masthead" class="navbar navbar-expand-lg navbar-dark bg-dark justify-content-between <%= placement_class %>" role="navigation" aria-label="masthead"> + <h1 class="sr-only"><%= application_name %></h1> + <%= render '/logo' %> + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#top-navbar-collapse" aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + <div class="collapse navbar-collapse justify-content-end" id="top-navbar-collapse"> <% if admin_host? %> <%= render '/admin_util_links' %> <% else %> <%= render '/user_util_links' %> <% end %> </div> - </div> -</nav> + </nav> +</header> diff --git a/app/views/_user_util_links.html.erb b/app/views/_user_util_links.html.erb index 782fcb5f1..db04aca6d 100644 --- a/app/views/_user_util_links.html.erb +++ b/app/views/_user_util_links.html.erb @@ -1,31 +1,29 @@ -<ul id="user_utility_links" class="nav navbar-nav navbar-right"> +<ul id="user_utility_links" class="navbar-nav ml-auto"> <%= render 'shared/locale_picker' if available_translations.size > 1 %> <% if user_signed_in? %> - <li> + <li class="nav-item"> <%= render_notifications(user: current_user) %> </li> - <li class="dropdown"> - <%= link_to hyrax.dashboard_profile_path(current_user), role: 'button', data: { toggle: 'dropdown' }, aria: { haspopup: true, expanded: false, controls: 'user-util-links' } do %> + <li class="nav-item dropdown"> + <%= link_to hyrax.dashboard_profile_path(current_user), class: 'nav-link dropdown-toggle', id: 'navbarDropdown', role: 'button', data: { toggle: 'dropdown' }, aria: { haspopup: true, expanded: false } do %> <span class="sr-only"><%= t("hyrax.toolbar.profile.sr_action") %></span> - <span class="hidden-xs"> <%= current_user.name %></span> + <%= current_user.name %> <span class="sr-only"> <%= t("hyrax.toolbar.profile.sr_target") %></span> - <span class="fa fa-user" aria-hidden="true"></span> - <span class="caret"></span> + <i class="fa fa-user" aria-hidden="true"></i> <% end %> - <ul id="user-util-links" class="dropdown-menu dropdown-menu-right" role="menu"> - <li><%= link_to t("hyrax.toolbar.dashboard.menu"), hyrax.dashboard_path %></li> - - <li class="divider"></li> - <% if Devise.mappings[:user]&.registerable? %> - <li><%= link_to t("hyku.toolbar.profile.edit_registration"), main_app.edit_user_registration_path %></li> + <div id="user-util-links" class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown"> + <a class="dropdown-item" href="<%= hyrax.dashboard_path %>"><%= t("hyrax.toolbar.dashboard.menu") %></a> + <div class="dropdown-divider"></div> + <% if Devise.mappings[:user]&.registerable? %> + <a class="dropdown-item" href="<%= main_app.edit_user_registration_path %>"><%= t("hyku.toolbar.profile.edit_registration") %></a> <% end %> - <li><%= link_to t("hyrax.toolbar.profile.logout"), main_app.destroy_user_session_path %></li> - </ul> - </li><!-- /.btn-group --> + <a class="dropdown-item" href="<%= main_app.destroy_user_session_path %>"><%= t("hyrax.toolbar.profile.logout") %></a> + </div> + </li> <% else %> - <li> - <%= link_to main_app.single_signon_index_path do %> - <span class="glyphicon glyphicon-log-in" aria-hidden="true"></span> <%= t("hyrax.toolbar.profile.login") %> + <li class="nav-item"> + <%= link_to main_app.single_signon_index_path, class: 'nav-link' do %> + <i class="fa fa-sign-in" aria-hidden="true"></i> <%= t("hyrax.toolbar.profile.login") %> <% end %> </li> <% end %> diff --git a/app/views/account_sign_up/new.html.erb b/app/views/account_sign_up/new.html.erb index dcc07cd8f..b63664813 100644 --- a/app/views/account_sign_up/new.html.erb +++ b/app/views/account_sign_up/new.html.erb @@ -4,7 +4,7 @@ <div class="row"> <div class="col-md-8"> - <%= form_for(@account, url: account_sign_up_path(@account), html: { class: 'form form-horizontal' }) do |f| %> + <%= form_for(@account, url: account_sign_up_path(@account), html: { class: 'form' }) do |f| %> <% if @account.errors.any? %> <div id="error_explanation" class="alert alert-danger"> <%= pluralize(@account.errors.count, "error") %> prohibited this repository from being saved: @@ -16,15 +16,15 @@ </div> <% end %> - <div class="form-group"> - <%= f.label :name, 'Short name', class: 'col-md-2 control-label' %> + <div class="form-group row"> + <%= f.label :name, 'Short name', class: 'col-md-2 col-form-label' %> <div class="col-md-10"> <%= f.text_field :name, class: 'form-control' %> - <span class="help-block">A single or hyphenated name used for technical aspects of the repository (e.g., "acme" or "acme-library").</span> + <small class="form-text text-muted">A single or hyphenated name used for technical aspects of the repository (e.g., "acme" or "acme-library").</small> </div> </div> - <%= f.submit class: 'btn btn-primary pull-right' %> + <%= f.submit class: 'btn btn-secondary float-right' %> <% end %> </div> </div> diff --git a/app/views/admin/accounts/edit.html.erb b/app/views/admin/accounts/edit.html.erb index e03fcb9fd..533aa0a07 100644 --- a/app/views/admin/accounts/edit.html.erb +++ b/app/views/admin/accounts/edit.html.erb @@ -4,9 +4,9 @@ <div class="row"> <div class="col-md-12"> - <div class="panel panel-default account-form"> + <div class="card account-form"> <%= simple_form_for([:admin, @account], url: admin_account_path, :html => { class: 'form' }) do |f| %> - <div class="panel-body"> + <div class="card-body"> <% if @account.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@account.errors.count, "error") %> prohibited this account from being saved:</h2> @@ -24,11 +24,11 @@ </div> <% current_account.public_settings.each do |key, value| %> - <%= render 'shared/settings', f:f, key: key, value: value %> + <%= render 'shared/settings', f: f, key: key, value: value %> <% end %> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-secondary float-right' %> </div> </div> <% end %> diff --git a/app/views/admin/groups/_form.html.erb b/app/views/admin/groups/_form.html.erb index f7363b22a..ad9af2a2b 100644 --- a/app/views/admin/groups/_form.html.erb +++ b/app/views/admin/groups/_form.html.erb @@ -5,15 +5,15 @@ target_path = admin_group_path(@group) end %> -<div class="panel panel-default"> +<div class="card"> <%= simple_form_for @group, url: target_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <%= f.input :humanized_name, label: t('hyku.admin.groups.label.humanized_name'), required: true %> <%= f.input :description, as: :text, label: t('hyku.admin.groups.label.description'), hint: '' %> </div> - <div class="panel-footer text-right"> + <div class="card-footer text-right"> <%= link_to t('simple_form.cancel'), admin_groups_path, class: 'btn btn-link action-cancel' %> - <%= f.submit class: 'btn btn-primary action-save' %> + <%= f.submit class: 'btn btn-secondary action-save' %> </div> <% end %> </div> diff --git a/app/views/admin/groups/_nav.html.erb b/app/views/admin/groups/_nav.html.erb index be0888668..17a25700c 100644 --- a/app/views/admin/groups/_nav.html.erb +++ b/app/views/admin/groups/_nav.html.erb @@ -2,10 +2,10 @@ <div class="panel-tab-wrapper"> <ul class="nav nav-tabs"> <% navigation_presenter.tabs.each do |tab| %> - <%= content_tag :li, role: 'presentation', class: tab.css_class do %> - <%= link_to tab.name, tab.path %> - <% end %> + <li class="nav-item" role="presentation"> + <%= link_to tab.name, tab.path, class: "nav-link #{'active' if tab.css_class == 'active'}" %> + </li> <% end %> </ul> - <%= link_to t('hyku.admin.groups.nav.index'), admin_groups_path, class: 'pull-right nav-escape-link' %> + <%= link_to t('hyku.admin.groups.nav.index'), admin_groups_path, class: 'float-right nav-escape-link' %> </div> diff --git a/app/views/admin/groups/_per_page.html.erb b/app/views/admin/groups/_per_page.html.erb index a2182bc09..4f9615dc9 100644 --- a/app/views/admin/groups/_per_page.html.erb +++ b/app/views/admin/groups/_per_page.html.erb @@ -5,7 +5,7 @@ <% if params[:page].present? %> <%= f.input :page, as: :hidden, input_html: { name: :page, value: params[:page] } %> <% end %> - <%= f.input :per, collection: [10, 25, 100], include_blank: false, required: false, selected: params[:per], input_html: { class: 'js-per-page__select', name: :per } %> + <%= f.input :per, collection: [10, 25, 100], include_blank: false, required: false, selected: params[:per], input_html: { class: 'js-per-page__select custom-select', name: :per } %> <%= t('hyku.admin.groups.label.per_page') %> - <%= f.submit class: 'btn btn-default js-per-page__submit' %> + <%= f.submit class: 'btn btn-secondary js-per-page__submit' %> <% end %> diff --git a/app/views/admin/groups/_search.html.erb b/app/views/admin/groups/_search.html.erb index 52fe58f83..26548adf5 100644 --- a/app/views/admin/groups/_search.html.erb +++ b/app/views/admin/groups/_search.html.erb @@ -5,11 +5,11 @@ <% if params[:page].present? %> <%= f.input :page, as: :hidden, input_html: { name: :page, value: params[:page] } %> <% end %> - <div class="form-group list-scope"> - <%= f.input :q, required: false, input_html: { class: 'list-scope__query', name: :q, value: params[:q] }, wrapper_html: { class: 'list-scope__query-wrapper'} %> + <div class="form-group mb-2 list-scope"> + <%= f.input :q, required: false, input_html: { class: 'form-control list-scope__query', name: :q, value: params[:q] }, wrapper_html: { class: 'list-scope__query-wrapper'} %> <% if params[:q].present? %> - <%= link_to content_tag(:span, '×'.html_safe, :'aria-hidden' => true), @target, class: 'close list-scope__reset', :'aria-label' => t('hyku.admin.groups.action.search.clear') %> + <%= link_to content_tag(:span, '×'.html_safe, :'aria-hidden' => true), @target, class: 'btn btn-sm btn-secondary close list-scope__reset', :'aria-label' => t('hyku.admin.groups.action.search.clear') %> <% end %> </div> - <%= f.submit class: 'btn btn-primary list-scope__submit' %> + <%= f.submit class: 'btn btn-primary mb-2 list-scope__submit' %> <% end %> diff --git a/app/views/admin/groups/index.html.erb b/app/views/admin/groups/index.html.erb index 8a1101e35..94c4c4324 100644 --- a/app/views/admin/groups/index.html.erb +++ b/app/views/admin/groups/index.html.erb @@ -1,6 +1,6 @@ <% content_for :page_title, construct_page_title(t('hyku.admin.groups.title.index'), t('hyku.admin.title')) %> <% provide :page_header do %> - <%if can? :edit, Hyrax::Group %> + <% if can? :edit, Hyrax::Group %> <h1> <span class="fa fa-users"></span> <%= t('hyku.admin.groups.title.index') %> @@ -13,8 +13,8 @@ <% end %> <% end %> -<div class="panel panel-default group-listing"> - <div class="panel-heading"> +<div class="card group-listing"> + <div class="card-header"> <% group_count = Hyrax::Group.count %> <% if group_count == 1 %> <%= t('hyku.admin.groups.describe_singular_quantity_html') %> @@ -22,16 +22,16 @@ <%= t('hyku.admin.groups.describe_quantity_html', number: group_count ) %> <% end %> <% if can? :create, Hyrax::Group %> - <%= link_to t('hyku.admin.groups.action.create'), new_admin_group_path, class: 'btn btn-primary pull-right new-group' %> + <%= link_to t('hyku.admin.groups.action.create'), new_admin_group_path, class: 'btn btn-primary float-right new-group' %> <% end %> </div> - <div class="panel-body"> + <div class="card-body"> <div class="container-fluid full-width-container"> <div class="row"> - <div class="col-sm-6"> + <div class="col-md-6"> <%= render 'per_page', target: admin_groups_path %> </div> - <div class="col-sm-6 text-right"> + <div class="col-md-6 text-right"> <%= render 'search', target: admin_groups_path %> </div> </div> @@ -53,7 +53,7 @@ <tr id=<%= "#{group.name}" %>> <td> <b><%= group.humanized_name %></b> - <p class='help-block'> + <p class='form-text text-muted'> <%= group.description_label %> </p> </td> @@ -71,7 +71,7 @@ </td> <td> <% if can? :edit, Hyrax::Group %> - <%= link_to t('hyku.admin.groups.action.edit'), edit_admin_group_path(group), id: "edit-#{group.name}-group", class: 'btn btn-default' %> + <%= link_to t('hyku.admin.groups.action.edit'), edit_admin_group_path(group), id: "edit-#{group.name}-group", class: 'btn btn-secondary' %> <% end %> </td> </tr> @@ -80,7 +80,7 @@ </table> </div> - <nav class="pull-right"> + <nav class="float-right"> <%= paginate @groups %> </nav> </div> diff --git a/app/views/admin/groups/new.html.erb b/app/views/admin/groups/new.html.erb index c20ee46fb..f2be4a36b 100644 --- a/app/views/admin/groups/new.html.erb +++ b/app/views/admin/groups/new.html.erb @@ -7,19 +7,19 @@ <% end %> <div class="panel-tab-wrapper"> <ul class="nav nav-tabs"> - <li role="presentation" class="active"> - <a href="javascript:void(0);"><%= t('hyku.admin.groups.nav.attributes') %></a> + <li class="nav-item" role="presentation"> + <a class="nav-link active" href="javascript:void(0);"><%= t('hyku.admin.groups.nav.attributes') %></a> </li> - <li role="presentation" class="disabled"> - <a href="javascript:void(0);"><%= t('hyku.admin.groups.nav.members') %></a> + <li class="nav-item" role="presentation"> + <a class="nav-link disabled" href="javascript:void(0);"><%= t('hyku.admin.groups.nav.members') %></a> </li> - <li role="presentation" class="disabled"> - <a href="javascript:void(0);"><%= t('hyku.admin.groups.nav.roles') %></a> + <li class="nav-item" role="presentation"> + <a class="nav-link disabled" href="javascript:void(0);"><%= t('hyku.admin.groups.nav.roles') %></a> </li> - <li role="presentation" class="disabled"> - <a href="javascript:void(0);"><%= t('hyku.admin.groups.nav.delete') %></a> + <li class="nav-item" role="presentation"> + <a class="nav-link disabled" href="javascript:void(0);"><%= t('hyku.admin.groups.nav.delete') %></a> </li> </ul> - <%= link_to t('hyku.admin.groups.nav.index'), admin_groups_path, class: 'pull-right nav-escape-link' %> + <%= link_to t('hyku.admin.groups.nav.index'), admin_groups_path, class: 'float-right nav-escape-link' %> </div> <%= render 'form' %> diff --git a/app/views/admin/groups/remove.html.erb b/app/views/admin/groups/remove.html.erb index b5380ed6c..b2a01abcf 100644 --- a/app/views/admin/groups/remove.html.erb +++ b/app/views/admin/groups/remove.html.erb @@ -7,15 +7,15 @@ <% end %> <%= render 'nav' %> -<div class="panel panel-default"> - <div class="panel-body"> - <blockquote class="callout callout-danger callout-with-action"> +<div class="card"> + <div class="card-body"> + <blockquote class="callout callout-danger"> <h3><%= t('hyku.admin.groups.title.delete', group: @group.humanized_name) %></h3> <p> - <%= t('hyku.admin.groups.action.remove.description') %> + <%= t('hyku.admin.groups.action.remove.description') %> </p> <div class="callout-action"> - <%= link_to t('hyku.admin.groups.action.remove.submit'), admin_group_path(@group), class: "btn btn-danger action-delete #{'disabled' if @group.default_group?}", method: :delete, data: { confirm: t('hyku.admin.groups.action.remove.confirmation') } %> + <%= link_to t('hyku.admin.groups.action.remove.submit'), admin_group_path(@group), class: "btn btn-danger action-delete #{'disabled' if @group.default_group?}", method: :delete, data: { confirm: t('hyku.admin.groups.action.remove.confirmation') } %> </div> </blockquote> </div> diff --git a/app/views/admin/groups/roles.html.erb b/app/views/admin/groups/roles.html.erb index 2e75f697b..b3aa2f89e 100644 --- a/app/views/admin/groups/roles.html.erb +++ b/app/views/admin/groups/roles.html.erb @@ -7,77 +7,78 @@ <% end %> <%= render '/admin/groups/nav' %> -<div class='panel panel-default'> - <div class='panel-body'> +<div class='card'> + <div class='card-body'> <p class='lead'><%= t('hyku.admin.groups.action.members.description') %></p> - <!-- BEGIN Current Group Roles --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h3 class='panel-title'><%= t('hyku.admin.groups.roles.title.current_group_roles') %></h3> - </div> + <!-- BEGIN Current Group Roles --> + <div class='card'> + <div class='card-header'> + <h3 class='card-title'><%= t('hyku.admin.groups.roles.title.current_group_roles') %></h3> + </div> - <div class='panel-body'> - <div class='table-responsive'> - <table class='table table-striped datatable group-roles-table current-group-roles'> - <thead> - <th><%= t('hyku.admin.groups.roles.label.name') %></th> - <th><%= t('hyku.admin.groups.roles.label.description') %></th> - <th><%= t('hyku.admin.groups.roles.label.action') %></th> - </thead> + <div class='card-body'> + <div class='table-responsive'> + <table class='table table-striped datatable group-roles-table current-group-roles'> + <thead> + <th><%= t('hyku.admin.groups.roles.label.name') %></th> + <th><%= t('hyku.admin.groups.roles.label.description') %></th> + <th><%= t('hyku.admin.groups.roles.label.action') %></th> + </thead> - <tbody> - <% @group.roles&.each do |role| %> - <tr id=<%= "assigned-role-#{role.id}" %>> - <td><%= role.name.titleize %></td> - <td><%= role.description_label %> - <td> - <%= simple_form_for :remove_role_from_group, url: admin_group_role_path(group_id: @group.to_param, role_id: role.id), method: :delete, html: { class: 'form' } do |f| %> - <%= f.submit class: 'btn btn-danger', disabled: @group.name == ::Ability.admin_group_name && role.name == 'admin', id: "remove-role-#{role.id}-from-group" %> - <% end %> - </td> - </tr> - <% end %> - </tbody> - </table> + <tbody> + <% @group.roles&.each do |role| %> + <tr id=<%= "assigned-role-#{role.id}" %>> + <td><%= role.name.titleize %></td> + <td><%= role.description_label %> + <td> + <%= simple_form_for :remove_role_from_group, url: admin_group_role_path(group_id: @group.to_param, role_id: role.id), method: :delete, html: { class: 'form' } do |f| %> + <%= f.submit class: 'btn btn-danger', disabled: @group.name == ::Ability.admin_group_name && role.name == 'admin', id: "remove-role-#{role.id}-from-group" %> + <% end %> + </td> + </tr> + <% end %> + </tbody> + </table> + </div> </div> </div> - </div> - <!-- END Current Group Roles --> + <!-- END Current Group Roles --> - <!-- BEGIN Add Role to Group --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h3 class='panel-title'><%= t('hyku.admin.groups.roles.title.add_group_roles') %></h3> - </div> + <!-- BEGIN Add Role to Group --> + <div class='card'> + <div class='card-header'> + <h3 class='card-title'><%= t('hyku.admin.groups.roles.title.add_group_roles') %></h3> + </div> - <div class='panel-body'> - <div class='table-responsive'> - <table class='table table-striped datatable group-roles-table add-group-roles'> - <thead> - <th><%= t('hyku.admin.groups.roles.label.name') %></th> - <th><%= t('hyku.admin.groups.roles.label.description') %></th> - <th><%= t('hyku.admin.groups.roles.label.action') %></th> - </thead> + <div class='card-body'> + <div class='table-responsive'> + <table class='table table-striped datatable group-roles-table add-group-roles'> + <thead> + <th><%= t('hyku.admin.groups.roles.label.name') %></th> + <th><%= t('hyku.admin.groups.roles.label.description') %></th> + <th><%= t('hyku.admin.groups.roles.label.action') %></th> + </thead> - <tbody> - <% @roles&.each do |role| %> - <tr id=<%= "available-role-#{role.id}" %>> - <td><%= role.name.titleize %></td> - <td><%= role.description_label %> - <td> - <%= simple_form_for :add_role_to_group, url: admin_group_roles_path(group_id: @group.to_param, role_id: role.id), method: :post, html: { class: 'form' } do |f| %> - <%= f.submit class: 'btn btn-success', id: "add-role-#{role.id}-to-group" %> - <% end %> - </td> - </tr> - <% end %> - </tbody> - </table> + <tbody> + <% @roles&.each do |role| %> + <tr id=<%= "available-role-#{role.id}" %>> + <td><%= role.name.titleize %></td> + <td><%= role.description_label %> + <td> + <%= simple_form_for :add_role_to_group, url: admin_group_roles_path(group_id: @group.to_param, role_id: role.id), method: :post, html: { class: 'form' } do |f| %> + <%= f.submit class: 'btn btn-success', id: "add-role-#{role.id}-to-group" %> + <% end %> + </td> + </tr> + <% end %> + </tbody> + </table> + </div> </div> </div> + <!-- END Add Role to Group --> </div> - <!-- END Add Role to Group --> </div> <script> diff --git a/app/views/admin/groups/users.html.erb b/app/views/admin/groups/users.html.erb index 75da95dee..4e0fbc807 100644 --- a/app/views/admin/groups/users.html.erb +++ b/app/views/admin/groups/users.html.erb @@ -7,33 +7,33 @@ <% end %> <%= render '/admin/groups/nav' %> -<div class="panel panel-default group-user-listing"> - <div class="panel-body"> +<div class="card group-user-listing"> + <div class="card-body"> <p class="lead"><%= t('hyku.admin.groups.action.members.description') %></p> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"><%= t('hyku.admin.groups.title.add_user') %></h3> + <div class="card"> + <div class="card-header"> + <h3 class="card-title"><%= t('hyku.admin.groups.title.add_user') %></h3> </div> - <div class="panel-body"> - <%= simple_form_for :user_search, url: hyrax.users_path, method: :get, html: { class: 'form-inline pull-left js-group-user-search' } do |f| %> + <div class="card-body"> + <%= simple_form_for :user_search, url: hyrax.users_path, method: :get, html: { class: 'form-inline float-left js-group-user-search' } do |f| %> <%= f.input :uq, name: :uq, required: false, input_html: { class: 'js-group-user-search__query', value: params[:uq] } %> - <%= f.submit class: 'btn btn-default js-group-user-search__submit' %> + <%= f.submit class: 'btn btn-secondary js-group-user-search__submit' %> <% end %> - <%= simple_form_for :add_user_to_group, url: admin_group_users_path(group_id: @group.to_param), method: :post, html: { class: 'form-inline pull-left js-group-user-add' } do |f| %> + <%= simple_form_for :add_user_to_group, url: admin_group_users_path(group_id: @group.to_param), method: :post, html: { class: 'form-inline float-left js-group-user-add' } do |f| %> <%= f.input :user_id, required: false, input_html: { class: 'js-group-user-add__id', name: :user_id } %> <%= f.submit class: 'btn btn-primary js-group-user-add__submit' %> <% end %> </div> </div> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"><%= t('hyku.admin.groups.title.list_members') %></h3> + <div class="card"> + <div class="card-header"> + <h3 class="card-title"><%= t('hyku.admin.groups.title.list_members') %></h3> </div> - <div class="panel-body"> + <div class="card-body"> <div class="container-fluid full-width-container"> <div class="row"> <div class="col-sm-6"> @@ -85,7 +85,7 @@ </table> </div> - <nav class="pull-right"> + <nav class="float-right"> <%= paginate @users %> </nav> </div> diff --git a/app/views/admin/work_types/edit.html.erb b/app/views/admin/work_types/edit.html.erb index 4595d2660..d325fb8f5 100644 --- a/app/views/admin/work_types/edit.html.erb +++ b/app/views/admin/work_types/edit.html.erb @@ -2,14 +2,14 @@ <h1><span class="fa fa-address-book"></span> <%= t('hyku.admin.work_types') %></h1> <% end %> -<div class="panel panel-default"> - <div class="panel-body"> +<div class="card"> + <div class="card-body"> <%= simple_form_for @site, url: '/admin/work_types' do |f| %> <% Hyrax.config.registered_curation_concern_types.each do |type| %> - <div class="checkbox"> - <label for="input-<%= type %>"> - <%= check_box_tag 'available_works[]', type, @site.available_works&.include?(type), id: "input-#{type}" %> - <span><%= type %></span><br /> + <div class="form-check"> + <input class="form-check-input" type="checkbox" value="<%= type %>" id="input-<%= type %>" name="available_works[]" <%= 'checked' if @site.available_works&.include?(type) %>> + <label class="form-check-label" for="input-<%= type %>"> + <%= type %> </label> </div> <% end %> diff --git a/app/views/advanced/_advanced_search_help.html.erb b/app/views/advanced/_advanced_search_help.html.erb new file mode 100644 index 000000000..52ef3a695 --- /dev/null +++ b/app/views/advanced/_advanced_search_help.html.erb @@ -0,0 +1,20 @@ +<%# OVERRIDE Blacklight Advanced Search v7.0.0 to add Search by date %> + +<div class='card card-default'> + <div class="card-body"> + <h4 class="card-title">Search tips</h4> + <ul class="advanced-help"> + <li>Select "match all" to require all fields.</li> + <li>Select "match any" to find at least one field.</li> + <li>Combine keywords and attributes to find specific items.</li> + <%# OVERRIDE begin %> + <li>Search by date with format: YYYYMMDD, YYYYMM or YYYY. Do not use "-", "/", or any other special characters.</li> + <%# OVERRIDE end %> + <li>Use quotation marks to search as a phrase.</li> + <li>Use "+" before a term to make it required. (Otherwise results matching only some of your terms may be included).</li> + <li>Use "-" before a word or phrase to exclude.</li> + <li>Use "OR", "AND", and "NOT" to create complex boolean logic. You can use parentheses in your complex expressions.</li> + <li>Truncation and wildcards are not supported - word-stemming is done automatically.</li> + </ul> + </div> +</div> diff --git a/app/views/blacklight_range_limit/_range_limit_panel.html.erb b/app/views/blacklight_range_limit/_range_limit_panel.html.erb new file mode 100644 index 000000000..738e6e3d7 --- /dev/null +++ b/app/views/blacklight_range_limit/_range_limit_panel.html.erb @@ -0,0 +1,125 @@ +<%- # requires solr_config local passed in + field_config = range_config(field_name) + label = facet_field_label(field_name) + + input_label_range_begin = field_config[:input_label_range_begin] || t("blacklight.range_limit.range_begin", field_label: label) + input_label_range_end = field_config[:input_label_range_end] || t("blacklight.range_limit.range_end", field_label: label) + maxlength = field_config[:maxlength] +-%> + + +<%# NOTE(dewey4iv): leaving the styling here for now so that Christy can test out what she wants this to look like %> +<style> + .year-input { + font-size: 1em; + } + + .limit_content.range_limit { + margin: .5em; + } + .limit_content.range_limit .range_input_wrapper { + margin: 5px 0; + } + + .limit_content.range_limit .range_input_wrapper span { + display: block; + line-height: 1; + } + + .limit_content.range_limit .range_input_wrapper:nth-child(2) { + margin-bottom: 25px; + } +</style> + +<div class="limit_content range_limit"> + <% if has_selected_range_limit?(field_name) %> + <ul class="current list-unstyled facet-values"> + <li class="selected"> + <span class="facet-label"> + <span class="selected"><%= range_display(field_name) %></span> + <%= link_to remove_range_param(field_name), :class=>"remove", :title => t('blacklight.range_limit.remove_limit') do %> + <span class="glyphicon glyphicon-remove"></span> + <span class="sr-only">[<%= t('blacklight.range_limit.remove_limit') %>]</span> + <% end %> + </span> + <span class="selected facet-count"><%= number_with_delimiter(@response.total) %></span> + </li> + </ul> + + <% end %> + + <% unless selected_missing_for_range_limit?(field_name) %> + <%= form_tag search_action_path, :method => :get, class: [BlacklightRangeLimit.classes[:form], "range_#{field_name}"].join(' ') do %> + <%= render_hash_as_hidden_fields(search_state.params_for_search.except(:page)) %> + + <!-- + we need to include a dummy search_field parameter if none exists, + to trick blacklight into displaying actual search results instead + of home page. Not a great solution, but easiest for now. + --> + <% unless params.has_key?(:search_field) %> + <%= hidden_field_tag("search_field", "dummy_range") %> + <% end %> + + <div class="range_input_wrapper"> + <span class="year-input">Between year:</span> + <%= render_range_input(field_name, :begin, input_label_range_begin, maxlength) %> + </div> + <div class="range_input_wrapper"> + <span class="year-input">and year:</span> + <%= render_range_input(field_name, :end, input_label_range_end, maxlength) %> + </div> + <%= submit_tag t('blacklight.range_limit.submit_limit'), class: "#{BlacklightRangeLimit.classes[:submit]} btn btn-default btn-block" %> + <% end %> + <% end %> + + <!-- no results profile if missing is selected --> + <% unless selected_missing_for_range_limit?(field_name) %> + <!-- + you can hide this if you want, but it has to be on page if you want + JS slider and calculated facets to show up, JS sniffs it. + --> + <div class="profile"> + <% if stats_for_field?(field_name) %> + <!-- No stats information found for field in search response --> + <% end %> + + <% if (min = range_results_endpoint(field_name, :min)) && + (max = range_results_endpoint(field_name, :max)) %> + <p class="range subsection <%= "slider_js" unless field_config[:slider_js] == false %>"> + <!-- Current results range from <span class="min"><%= range_results_endpoint(field_name, :min) %></span> to <span class="max"><%= range_results_endpoint(field_name, :max) %></span> --> + </p> + + <% if field_config[:segments] != false %> + <div class="distribution subsection <%= 'chart_js' unless field_config[:chart_js] == false %>"> + <!-- + if we already fetched segments from solr, display them + here. Otherwise, display a link to fetch them, which JS + will AJAX fetch. + --> + <% if solr_range_queries_to_a(field_name).length > 0 %> + + <%= render(:partial => "blacklight_range_limit/range_segments", :locals => {:solr_field => field_name}) %> + + <% else %> + <%= link_to('View distribution', main_app.url_for(search_state.to_h.merge(action: 'range_limit', range_field: field_name, range_start: min, range_end: max)), :class => "load_distribution") %> + <% end %> + </div> + <% end %> + <% end %> + + <% if (stats = stats_for_field(field_name)) %> + <ul class="missing list-unstyled facet-values subsection"> + <li> + <span class="facet-label"> + <%= link_to BlacklightRangeLimit.labels[:missing], add_range_missing(field_name) %> + </span> + <span class="facet-count"> + <%= number_with_delimiter(stats["missing"]) %> + </span> + </li> + </ul> + <% end %> + </div> + <% end %> +</div> diff --git a/app/views/catalog/_index_gallery_collection_wrapper.html.erb b/app/views/catalog/_index_gallery_collection_wrapper.html.erb index e55b72ff3..339cb6b89 100644 --- a/app/views/catalog/_index_gallery_collection_wrapper.html.erb +++ b/app/views/catalog/_index_gallery_collection_wrapper.html.erb @@ -1,5 +1,5 @@ -<%# OVERRIDE Hyrax 3.4.1: make collection thumbnail a link so it matches works %> -<div class="document col-xs-6 col-md-3"> +<%# OVERRIDE Hyrax v5.0.0rc2: make collection thumbnail a link so it matches works %> +<div class="document col-6 col-md-3"> <div class="thumbnail"> <% value = collection_thumbnail(document, {}, counter: document_counter_with_offset(document_counter)) %> <%= link_to value, generate_work_url(document.to_h, request)%> diff --git a/app/views/catalog/_index_header_default.html.erb b/app/views/catalog/_index_header.html.erb similarity index 83% rename from app/views/catalog/_index_header_default.html.erb rename to app/views/catalog/_index_header.html.erb index 89d92ad8c..ca310a3d7 100644 --- a/app/views/catalog/_index_header_default.html.erb +++ b/app/views/catalog/_index_header.html.erb @@ -1,9 +1,9 @@ -<%# OVERRIDE blacklight-gallery v0.12.0: - TODO: commented out because bookmarks fail for shared search tenant. +<%# OVERRIDE Blacklight v7.35.0: + TODO: commented out because bookmarks fail for shared search tenant. If a bookmark is saved in shared tenant, it errors on subsequent views. %> <%# header bar for doc items in index view -%> -<div class="documentHeader row"> +<header class="documentHeader row"> <%# main title container for doc partial view How many bootstrap columns need to be reserved for bookmarks control depends on size. @@ -12,13 +12,15 @@ <% # bookmark functions for items/docs -%> <%#= render_index_doc_actions document, wrapping_class: "index-document-functions col-sm-3 col-lg-2" %> <% end %> + <h3 class="index_title document-title-heading <%= document_actions.present? ? "col-sm-9 col-lg-10" : "col-md-12" %>"> <% if counter = document_counter_with_offset(document_counter) %> <span class="document-counter"> <%= t('blacklight.search.documents.counter', counter: counter) %> </span> <% end %> - <%= link_to_document document, document_show_link_field(document), counter: counter %> + <%= link_to_document document, counter: counter %> </h3> + <%= document_actions %> -</div> +</header> diff --git a/app/views/catalog/_index_header_list_collection.html.erb b/app/views/catalog/_index_header_list_collection.html.erb index d6860cc46..62a809d25 100644 --- a/app/views/catalog/_index_header_list_collection.html.erb +++ b/app/views/catalog/_index_header_list_collection.html.erb @@ -1,4 +1,8 @@ -<div class="search-results-title-row"> - <h4 class="search-result-title"><%= link_to document.title_or_label, generate_work_url(document.to_h, request) %></h4> +<%# OVERRIDE Hyrax v5.0.0rc2 %> + +<div class="search-results-title-row col-12 d-flex flex-row align-items-center pb-2"> + <%# OVERRIDE begin %> + <h3 class="search-result-title mb-0 pr-3"><%= link_to document.title_or_label, generate_work_url(document.to_h, request) %></h3> + <%# OVERRIDE end %> <%= Hyrax::CollectionPresenter.new(document, current_ability).collection_type_badge %> </div> diff --git a/app/views/catalog/_index_header_list_default.html.erb b/app/views/catalog/_index_header_list_default.html.erb index a215dc20c..bad9d9e9d 100644 --- a/app/views/catalog/_index_header_list_default.html.erb +++ b/app/views/catalog/_index_header_list_default.html.erb @@ -1,10 +1,10 @@ -<%# OVERRIDE Hyrax 3.4.0 to support shared search %> +<%# OVERRIDE Hyrax v5.0.0rc2 to support shared search %> <% model = document.hydra_model %> -<div class="search-results-title-row"> - <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %> - <h4 class="search-result-title"><%= link_to document.title_or_label, generate_work_url(document, request) %></h4> - <%= Hyrax::CollectionPresenter.new(document, current_ability).collection_type_badge %> - <% else %> - <h4 class="search-result-title"><%= link_to document.title_or_label, generate_work_url(document, request) %></h4> - <% end %> +<div class="search-results-title-row col-12 d-flex flex-row align-items-center pb-2"> + <% if model == Hyrax::PcdmCollection || model < Hyrax::PcdmCollection %> + <h4 class="search-result-title"><%= link_to document.title_or_label, generate_work_url(document, request) %></h4> + <%= Hyrax::CollectionPresenter.new(document, current_ability).collection_type_badge %> + <% else %> + <h4 class="search-result-title"><%= link_to document.title_or_label, generate_work_url(document, request) %></h4> + <% end %> </div> diff --git a/app/views/catalog/_index_masonry_default.html.erb b/app/views/catalog/_index_masonry_default.html.erb deleted file mode 100644 index dfec1309c..000000000 --- a/app/views/catalog/_index_masonry_default.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -<%# OVERRIDE blacklight-gallery: for shared search URLs %> -<%= link_to document.title_or_label, generate_work_url(document.to_h, request) %> diff --git a/app/views/catalog/_thumbnail_list_collection.html.erb b/app/views/catalog/_thumbnail_list_collection.html.erb index d06f1a488..65b33703a 100644 --- a/app/views/catalog/_thumbnail_list_collection.html.erb +++ b/app/views/catalog/_thumbnail_list_collection.html.erb @@ -1,5 +1,5 @@ <%# Override Hyrax 3.4.1 to remove thumbnail link supression and use default collection thumbnail %> -<div class="col-md-2"> +<div class="col-md-3"> <% value = collection_thumbnail(document, {}, counter: document_counter_with_offset(document_counter)) %> <%= link_to value, generate_work_url(document.to_h, request)%> </div> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index d03d87c17..ce6aad1b8 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -1,20 +1,20 @@ <h2 class="text-center">Forgot your password?</h2> -<div class="row center-block"> - <div class="col-md-6 col-md-offset-3"> +<div class="row justify-content-center"> + <div class="col-md-6"> <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="form-group"> <%= f.label :email %><br /> - <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-control" %> + <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-control" %> </div> <div class="form-group text-center"> - <%= f.submit "Send me reset password instructions", class: 'btn btn-primary' %> + <%= f.submit "Send me reset password instructions", class: 'btn btn-primary' %> </div> <% end %> <div class="text-center"> <%= render "devise/shared/links" %> </div> </div> -</div> \ No newline at end of file +</div> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 9f9b48c79..316577673 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -1,19 +1,21 @@ -<div class="row col-md-9 account-form registration"> +<div class="row justify-content-center"> + <div class="col-md-9 account-form registration"> <h2><%= t(".sign_up_header") %></h2> - <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: 'form-horizontal' }) do |f| %> - <%= f.error_notification %> + <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: '' }) do |f| %> + <%= f.error_notification %> - <div class="form-inputs"> - <%= f.input :display_name, required: true, wrapper: :inline %> - <%= f.input :email, required: true, autofocus: true, wrapper: :inline %> - <%= f.input :password, required: true, wrapper: :inline %> - <%= f.input :password_confirmation, required: true, wrapper: :inline %> - </div> + <div class="form-inputs"> + <%= f.input :display_name, required: true, wrapper: :inline %> + <%= f.input :email, required: true, autofocus: true, wrapper: :inline %> + <%= f.input :password, required: true, wrapper: :inline %> + <%= f.input :password_confirmation, required: true, wrapper: :inline %> + </div> - <div class="form-actions"> - <%= render 'devise/shared/links' %> - <%= f.button :submit, t(".sign_up") %> - </div> + <div class="form-actions"> + <%= render 'devise/shared/links' %> + <%= f.button :submit, t(".sign_up") %> + </div> <% end %> + </div> </div> diff --git a/app/views/devise/registrations/registrations/new.html.erb b/app/views/devise/registrations/registrations/new.html.erb index 4ed469233..34dec3168 100644 --- a/app/views/devise/registrations/registrations/new.html.erb +++ b/app/views/devise/registrations/registrations/new.html.erb @@ -1,26 +1,24 @@ -<h2 class="text-center pt-40 pb-40"><%= t(".sign_up_header") %></h2> -<div class="row center-block"> - <div class="col-md-8 col-md-offset-2"> - <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: 'form-horizontal' }) do |f| %> - <small> +<h2 class="text-center pt-5 pb-5"><%= t(".sign_up_header") %></h2> +<div class="row justify-content-center"> + <div class="col-md-8"> + <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: 'form' }) do |f| %> + <small> <%= f.error_notification %> - </small> + </small> - <div class="form-inputs"> - <%= f.input :display_name, required: true, wrapper: :inline %> - <%= f.input :email, required: true, autofocus: true, wrapper: :inline %> - <%= f.input :password, required: true, wrapper: :inline %> - <%= f.input :password_confirmation, required: true, wrapper: :inline %> - </div> + <div class="form-inputs"> + <%= f.input :display_name, required: true, wrapper: :inline %> + <%= f.input :email, required: true, autofocus: true, wrapper: :inline %> + <%= f.input :password, required: true, wrapper: :inline %> + <%= f.input :password_confirmation, required: true, wrapper: :inline %> + </div> - <div class="form-group text-center"> - <%= render 'devise/shared/links' %> - </div> - <div class="text-center pb-40"> - <%= f.button :submit, t(".sign_up") %> - </div> + <div class="form-group text-center"> + <%= render 'devise/shared/links' %> + </div> + <div class="text-center pb-5"> + <%= f.button :submit, t(".sign_up") %> </div> <% end %> </div> </div> - diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 090e2cbd8..73c0cc605 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,31 +1,30 @@ +<h2 class="text-center">Log in</h2> +<div class="row justify-content-center"> + <div class="col-md-6"> + <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> + <div class="form-group"> + <%= f.label :email %><br /> + <%= f.email_field :email, autofocus: true, class: "form-control" %> + </div> - <h2 class="text-center">Log in</h2> - <div class="row center-block"> - <div class="col-md-6 col-md-offset-3"> - <%= form_for(resource, as: resource_name, url: session_path(resource_name), class: "form-horizontal") do |f| %> - <div class="form-group"> - <%= f.label :email %><br /> - <%= f.email_field :email, autofocus: true, class: "form-control" %> - </div> - - <div class="form-group"> - <%= f.label :password, class: "control-label" %><br /> - <%= f.password_field :password, autocomplete: "off", class: "form-control" %> - </div> - - <% if devise_mapping.rememberable? -%> - <div class="form-group text-center"> - <%= f.check_box :remember_me %> - <%= f.label :remember_me, class: "control-label" %> - </div> - <% end -%> + <div class="form-group"> + <%= f.label :password, class: "control-label" %><br /> + <%= f.password_field :password, autocomplete: "off", class: "form-control" %> + </div> + <% if devise_mapping.rememberable? -%> <div class="form-group text-center"> - <%= f.submit "Log in", class: 'btn btn-primary' %> + <%= f.check_box :remember_me %> + <%= f.label :remember_me, class: "control-label" %> </div> - <% end %> - <div class="text-center"> - <%= render "devise/shared/links" %> + <% end -%> + + <div class="form-group text-center"> + <%= f.submit "Log in", class: 'btn btn-primary' %> </div> + <% end %> + <div class="text-center"> + <%= render "devise/shared/links" %> </div> - </div> \ No newline at end of file + </div> +</div> diff --git a/app/views/hyrax/admin/admin_sets/_form_participant_table.html.erb b/app/views/hyrax/admin/admin_sets/_form_participant_table.html.erb index 07903899c..d355978e5 100644 --- a/app/views/hyrax/admin/admin_sets/_form_participant_table.html.erb +++ b/app/views/hyrax/admin/admin_sets/_form_participant_table.html.erb @@ -1,38 +1,40 @@ -<%# OVERRIDE Hyrax v3.4.2 Filter out Role accesses as they should never be removed %> -<h3><%= t(".#{access}.title") %></h3> -<p><%= t(".#{access}.help") %></p> -<%# OVERRIDE: use custom method to filter by access as well as filter out rolify Roles %> -<% if @form.filter_access_grants_by_access(filter).any? %> - <%# OVERRIDE: use custom access-specific class in order to differentiate between access tables %> - <table class='table table-striped share-status <%= "#{access}-table" %>'> - <thead> - <tr> - <th><%= t(".#{access}.agent_name") %></th> - <th><%= t(".#{access}.type") %></th> - <th><%= t(".#{access}.action") %></th> - </tr> - </thead> - <tbody> - <%# OVERRIDE: use custom method to filter by access as well as filter out rolify Roles %> - <% @form.filter_access_grants_by_access(filter).each do |g| %> +<%# OVERRIDE Hyrax v5.0.0rc2 Filter out Role accesses as they should never be removed %> +<div class="mb-4"> + <h3 class="h4"><%= t(".#{access}.title") %></h3> + <p><%= t(".#{access}.help") %></p> + <%# OVERRIDE: use custom method to filter by access as well as filter out rolify Roles %> + <% if @form.filter_access_grants_by_access(filter).any? %> + <%# OVERRIDE: use custom access-specific class in order to differentiate between access tables %> + <table class='table table-striped share-status <%= "#{access}-table" %>'> + <thead> <tr> - <td data-agent="<%= g.agent_id %>"><%= g.label %></td> - <td><%= g.agent_type.titleize %></td> - <td> - <%# OVERRIDE: remove disabled class from button to fix styling %> - <% if g.admin_group? && g.access == Hyrax::PermissionTemplateAccess::MANAGE %> - <%= button_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-danger', disabled: true, title: t('hyrax.admin.admin_sets.form.permission_destroy_errors.admin_group') %> - <% else %> - <%= button_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-danger' %> - <% end %> - </td> + <th><%= t(".#{access}.agent_name") %></th> + <th><%= t(".#{access}.type") %></th> + <th><%= t(".#{access}.action") %></th> </tr> - <% end %> - </tbody> - </table> -<% else %> - <p><em><%= t(".#{access}.empty") %></em></p> -<% end %> -<%= button_tag t('.allow_all_registered'), - class: 'btn btn-info', - data: { behavior: 'add-registered-users' } if access == 'depositors' %> + </thead> + <tbody> + <%# OVERRIDE: use custom method to filter by access as well as filter out rolify Roles %> + <% @form.filter_access_grants_by_access(filter).each do |g| %> + <tr> + <td data-agent="<%= g.agent_id %>"><%= g.label %></td> + <td><%= g.agent_type.titleize %></td> + <td> + <%# OVERRIDE: remove disabled class from button to fix styling %> + <% if g.admin_group? && g.access == Hyrax::PermissionTemplateAccess::MANAGE %> + <%= button_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger disabled', disabled: true, title: t('hyrax.admin.admin_sets.form.permission_destroy_errors.admin_group') %> + <% else %> + <%= button_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger' %> + <% end %> + </td> + </tr> + <% end %> + </tbody> + </table> + <% else %> + <p><em><%= t(".#{access}.empty") %></em></p> + <% end %> + <%= button_tag t('.allow_all_registered'), + class: 'btn btn-primary', + data: { behavior: 'add-registered-users' } if access == 'depositors' %> +</div> diff --git a/app/views/hyrax/admin/admin_sets/_form_participants.html.erb b/app/views/hyrax/admin/admin_sets/_form_participants.html.erb index 5e33a06c1..60c684a83 100644 --- a/app/views/hyrax/admin/admin_sets/_form_participants.html.erb +++ b/app/views/hyrax/admin/admin_sets/_form_participants.html.erb @@ -1,10 +1,10 @@ -<%# OVERRIDE Hyrax v3.4.2 Use Hyrax::Groups for groups select box %> +<%# OVERRIDE Hyrax v5.0.0rc2 Use Hyrax::Groups for groups select box %> <div id="participants" class="tab-pane"> - <div class="panel panel-default labels"> - <div class="panel-body"> - <h2><%= t('.add_participants') %></h2> + <div class="card labels edit-sharing-tab"> + <div class="card-body"> + <h2 class="h3"><%= t('.add_participants') %></h2> <% access_options = options_for_select([['Manager', 'manage'], ['Depositor', 'deposit'], ['Viewer', 'view']]) %> - <%= simple_form_for @form.permission_template, + <%= simple_form_for collection_permission_template_form_for(form: @form), url: [hyrax, :admin, @form, :permission_template], html: { id: 'group-participants-form' } do |f| %> <div class="clearfix spacer"> @@ -27,14 +27,14 @@ { prompt: "Select a role..." }, class: 'form-control' %> - <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info' %> + <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-secondary ml-2' %> </div> </div> <% end %> </div> <% end %> - <%= simple_form_for @form.permission_template, + <%= simple_form_for collection_permission_template_form_for(form: @form), url: [hyrax, :admin, @form, :permission_template], html: { id: 'user-participants-form' } do |f| %> <%= f.fields_for 'access_grants_attributes', @@ -53,19 +53,19 @@ { prompt: "Select a role..." }, class: 'form-control' %> - <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info' %> - <p class="help-block"><%= t('hyrax.admin.admin_sets.form.note') %></p> + <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-secondary ml-2' %> + <p class="form-text"><%= t('hyrax.admin.admin_sets.form.note') %></p> </div> </div> <% end %> <% end %> - <fieldset class="admin-set-participants"> - <legend><%= t(".current_participants") %></legend> + <h2 class="h3"><%= t(".current_participants") %></h2> + <fieldset class="admin-set-participants section-collection-sharing"> <%= render 'form_participant_table', access: 'managers', filter: :manage? %> <%= render 'form_participant_table', access: 'depositors', filter: :deposit? %> <%= render 'form_participant_table', access: 'viewers', filter: :view? %> </fieldset> - </div> + </div><!-- /.card-body --> </div> </div> diff --git a/app/views/hyrax/admin/appearances/_banner_image_form.html.erb b/app/views/hyrax/admin/appearances/_banner_image_form.html.erb index c92d3b4c0..a5a0ee11e 100644 --- a/app/views/hyrax/admin/appearances/_banner_image_form.html.erb +++ b/app/views/hyrax/admin/appearances/_banner_image_form.html.erb @@ -1,19 +1,20 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <% require_image = @form.banner_image? ? false : true %> <%# Upload Banner Image %> <%= f.input :banner_image, as: :file, wrapper: :vertical_file_input, required: require_image, hint: t('hyrax.admin.appearances.show.forms.banner_image.hint') %> <%= f.input :banner_image_text, required: true, as: :text, label: 'Banner image alt text' %> - <%= image_tag @form.banner_image.url, class: "img-responsive" if @form.banner_image? %> + <%= image_tag @form.banner_image.url, class: "img-fluid" if @form.banner_image? %> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right' %> </div> <% end %> + <% if @form.banner_image? %> - <div class="panel-footer"> + <div class="card-footer"> <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> <%= f.submit 'Remove banner image', class: 'btn btn-danger', name: :remove_banner_image %> <% end %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_color_input.html.erb b/app/views/hyrax/admin/appearances/_color_input.html.erb index b8a7783b8..7b735a4c5 100644 --- a/app/views/hyrax/admin/appearances/_color_input.html.erb +++ b/app/views/hyrax/admin/appearances/_color_input.html.erb @@ -9,7 +9,7 @@ <div class='col-lg-2'> <%= link_to 'Restore Default', '#color', - class: "btn btn-default restore-default-color #{'with-color-hint' if !missing_translation(hint)}", + class: "btn btn-secondary restore-default-color #{'with-color-hint' if !missing_translation(hint)}", data: { default_target: color_name } %> </div> </div> diff --git a/app/views/hyrax/admin/appearances/_custom_css_form.html.erb b/app/views/hyrax/admin/appearances/_custom_css_form.html.erb index 6fdea57c6..f4f5d980f 100644 --- a/app/views/hyrax/admin/appearances/_custom_css_form.html.erb +++ b/app/views/hyrax/admin/appearances/_custom_css_form.html.erb @@ -1,5 +1,5 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <%= f.input :custom_css_block, required: false, as: :text, label: 'Add Custom CSS Below' %> <script> var custom_css_block = document.getElementById('admin_appearance_custom_css_block') @@ -12,7 +12,7 @@ }); </script> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right', data: { confirm: t('hyrax.admin.appearances.show.forms.custom_css.confirm') } %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right', data: { confirm: t('hyrax.admin.appearances.show.forms.custom_css.confirm') } %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_default_colors_form.html.erb b/app/views/hyrax/admin/appearances/_default_colors_form.html.erb index 9a8251957..323ac98fc 100644 --- a/app/views/hyrax/admin/appearances/_default_colors_form.html.erb +++ b/app/views/hyrax/admin/appearances/_default_colors_form.html.erb @@ -1,11 +1,11 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body defaultable-colors"> - <% @form.class::DEFAULT_COLORS.each do |color_name, hex| %> + <div class="card-body defaultable-colors"> + <% @form.default_colors.each do |color_name, hex| %> <%= render 'color_input', f: f, color_name: color_name, hex: hex %> <% end %> </div> - <div class="panel-footer"> - <%= link_to 'Restore All Defaults', '#color', class: 'btn btn-default restore-all-default-colors' %> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= link_to 'Restore All Defaults', '#color', class: 'btn btn-secondary restore-all-default-colors' %> + <%= f.submit class: 'btn btn-primary float-right' %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb b/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb index 3df04aba3..24abeac39 100644 --- a/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb +++ b/app/views/hyrax/admin/appearances/_default_fonts_form.html.erb @@ -1,17 +1,17 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body defaultable-fonts"> - <% df = @form.class::DEFAULT_FONTS %> + <div class="card-body defaultable-fonts"> + <% df = @form.default_fonts %> <% font = f.object.body_font %> <%= f.input :body_font, label: 'Select Body Font', required: false, input_html: { class: 'font-fields', data: { default_value: df['body_font'] } } %> - <%= link_to 'Restore Default', '#font', class: 'btn btn-default restore-default-font', data: { default_target: 'body_font' } %> + <%= link_to 'Restore Default', '#font', class: 'btn btn-secondary restore-default-font', data: { default_target: 'body_font' } %> <%= f.input :headline_font, label: 'Select Header Font', required: false, input_html: { class: 'font-fields', data: { default_value: df['headline_font'] } } %> - <%= link_to 'Restore Default', '#font', class: 'btn btn-default restore-default-font', data: { default_target: 'headline_font' } %> + <%= link_to 'Restore Default', '#font', class: 'btn btn-secondary restore-default-font', data: { default_target: 'headline_font' } %> </div> - <div class="panel-footer"> - <%= link_to 'Restore All Defaults', '#font', class: 'btn btn-default restore-all-default-fonts' %> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= link_to 'Restore All Defaults', '#font', class: 'btn btn-secondary restore-all-default-fonts' %> + <%= f.submit class: 'btn btn-primary float-right' %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_default_images_form.html.erb b/app/views/hyrax/admin/appearances/_default_images_form.html.erb index 8e409fff5..dc2da00e3 100644 --- a/app/views/hyrax/admin/appearances/_default_images_form.html.erb +++ b/app/views/hyrax/admin/appearances/_default_images_form.html.erb @@ -1,20 +1,20 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <%= f.input :default_collection_image, as: :file, wrapper: :vertical_file_input, hint: t('hyrax.admin.appearances.show.forms.default_images.hint'), required: false %> <%= f.input :default_collection_image_text, as: :text, label: 'Default collection image alt text', required: false %> - <%= image_tag @form.default_collection_image.url, class: "img-responsive" if @form.default_collection_image? %> + <%= image_tag @form.default_collection_image.url, class: "img-fluid" if @form.default_collection_image? %> <%= f.input :default_work_image, as: :file, wrapper: :vertical_file_input, hint: t('hyrax.admin.appearances.show.forms.default_images.hint'), required: false %> <%= f.input :default_work_image_text, as: :text, label: 'Default work image alt text', required: false %> - <%= image_tag @form.default_work_image.url, class: "img-responsive" if @form.default_work_image? %> + <%= image_tag @form.default_work_image.url, class: "img-fluid" if @form.default_work_image? %> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right' %> </div> <% end %> <% if @form.default_collection_image? || @form.default_work_image? %> - <div class="panel-footer"> + <div class="card-footer"> <% if @form.default_collection_image? %> <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> <%= f.submit 'Remove default collection image', class: 'btn btn-danger', name: :remove_default_collection_image %> @@ -26,4 +26,4 @@ <% end %> <% end %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_directory_image_form.html.erb b/app/views/hyrax/admin/appearances/_directory_image_form.html.erb index cc29927ee..18f6b25fb 100644 --- a/app/views/hyrax/admin/appearances/_directory_image_form.html.erb +++ b/app/views/hyrax/admin/appearances/_directory_image_form.html.erb @@ -1,19 +1,19 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <% require_image = @form.directory_image? ? false : true %> <%# Upload Directory Image %> <%= f.input :directory_image, as: :file, wrapper: :vertical_file_input, required: require_image, hint: t('hyrax.admin.appearances.show.forms.directory_image.hint') %> <%= f.input :directory_image_text, required: true, as: :text, label: 'Directory image alt text' %> - <%= image_tag @form.directory_image.url, class: "img-responsive" if @form.directory_image? %> + <%= image_tag @form.directory_image.url, class: "img-fluid" if @form.directory_image? %> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right' %> </div> <% end %> <% if @form.directory_image? %> - <div class="panel-footer"> + <div class="card-footer"> <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> <%= f.submit 'Remove directory image', class: 'btn btn-danger', name: :remove_directory_image %> <% end %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_favicon_form.html.erb b/app/views/hyrax/admin/appearances/_favicon_form.html.erb index 1b526ff10..157a2c404 100644 --- a/app/views/hyrax/admin/appearances/_favicon_form.html.erb +++ b/app/views/hyrax/admin/appearances/_favicon_form.html.erb @@ -1,17 +1,17 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <% require_image = @form.favicon? ? false : true %> <%= f.input :favicon, as: :file, wrapper: :vertical_file_input, hint: t('hyrax.admin.appearances.show.forms.favicon.hint') %> - <%= image_tag @form.favicon.url, class: "img-responsive" if @form.favicon? %> + <%= image_tag @form.favicon.url, class: "img-fluid" if @form.favicon? %> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right' %> </div> <% end %> <% if @form.favicon? %> - <div class="panel-footer"> + <div class="card-footer"> <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> <%= f.submit 'Remove favicon', class: 'btn btn-danger', name: :remove_favicon %> <% end %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_logo_image_form.html.erb b/app/views/hyrax/admin/appearances/_logo_image_form.html.erb index 3b21357f4..2d1bc9be4 100644 --- a/app/views/hyrax/admin/appearances/_logo_image_form.html.erb +++ b/app/views/hyrax/admin/appearances/_logo_image_form.html.erb @@ -1,19 +1,19 @@ <%= simple_form_for @form, url: admin_appearance_path do |f| %> - <div class="panel-body"> + <div class="card-body"> <% require_image = @form.logo_image? ? false : true %> <%# Upload Logo Image %> <%= f.input :logo_image, as: :file, wrapper: :vertical_file_input, required: require_image, hint: t('hyrax.admin.appearances.show.forms.logo_image.hint') %> <%= f.input :logo_image_text, required: true, as: :text, label: 'Logo image alt text' %> - <%= image_tag @form.logo_image.url, class: "img-responsive" if @form.logo_image? %> + <%= image_tag @form.logo_image.url, class: "img-fluid" if @form.logo_image? %> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer"> + <%= f.submit class: 'btn btn-primary float-right' %> </div> <% end %> <% if @form.logo_image? %> - <div class="panel-footer"> + <div class="card-footer"> <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> <%= f.submit 'Remove logo image', class: 'btn btn-danger', name: :remove_logo_image %> <% end %> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/admin/appearances/_theme_form.html.erb b/app/views/hyrax/admin/appearances/_theme_form.html.erb index d79a03c13..9d0a0d662 100644 --- a/app/views/hyrax/admin/appearances/_theme_form.html.erb +++ b/app/views/hyrax/admin/appearances/_theme_form.html.erb @@ -1,5 +1,5 @@ <%= simple_form_for @form.site, url: main_app.site_path(@form.site) do |f| %> - <div class="panel-body"> + <div class="card-body"> <div class="row"> <div class="col-sm-6"> <% home_options = @home_theme_names.map { |g| [g[0], g[1], {'data-image' => image_path("themes/#{g[1]}/#{g[1]}.jpg")}] } %> @@ -23,12 +23,12 @@ </ul> </div> <div id="home-wireframe" class="col-sm-6"> - <%= image_tag "themes/default_home/default_home", class: "img-responsive" %> + <%= image_tag "themes/default_home/default_home", class: "img-fluid" %> </div> </div> <hr /> <div class="row"> - <div class="col-sm-6"> + <div class="col-md-6"> <% search_options = @search_themes.map { |s| [s[0], s[1], { 'data-image' => image_path("themes/search/#{s[1]}.jpg") }] } %> <%= f.input :search_theme, label: 'Search Results Page Theme' do %> <%= f.select :search_theme, search_options, {}, { prompt: 'Select search results page theme...', class: 'form-control' } %> @@ -38,8 +38,8 @@ <li>This will select a default view for the search results page. Users can select their preferred views on the search results page that will override this selection.</li> </ul> </div> - <div id="search-wireframe" class="col-sm-6"> - <%= image_tag "themes/search/list_view.jpg", class: "img-responsive" %> + <div id="search-wireframe" class="col-md-6"> + <%= image_tag "themes/search/list_view.jpg", class: "img-fluid" %> </div> </div> <hr /> @@ -56,12 +56,12 @@ </ul> </div> <div id="show-wireframe" class="col-sm-6"> - <%= image_tag "themes/default_show/default_show", class: "img-responsive" %> + <%= image_tag "themes/default_show/default_show", class: "img-fluid" %> </div> </div> <hr /> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer text-right"> + <%= f.submit class: 'btn btn-secondary' %> </div> <% end %> diff --git a/app/views/hyrax/admin/appearances/show.html.erb b/app/views/hyrax/admin/appearances/show.html.erb index 8194f2890..cd37788ab 100644 --- a/app/views/hyrax/admin/appearances/show.html.erb +++ b/app/views/hyrax/admin/appearances/show.html.erb @@ -4,88 +4,88 @@ <div class="row"> <div class="col-md-12"> - <div class="panel panel-default tabs" id="admin-set-controls"> + <div class="card tabs" id="admin-set-controls"> <ul class="nav nav-tabs" role="tablist"> - <li class="active"> - <a href="#logo_image" role="tab" data-toggle="tab"><%= t('.tabs.logo') %></a> + <li class="nav-item"> + <a class="nav-link active" href="#logo_image" role="tab" data-toggle="tab"><%= t('.tabs.logo') %></a> </li> - <li> - <a href="#favicon" role="tab" data-toggle="tab"><%= t('.tabs.favicon') %></a> + <li class="nav-item"> + <a class="nav-link" href="#favicon" role="tab" data-toggle="tab"><%= t('.tabs.favicon') %></a> </li> - <li> - <a href="#banner_image" role="tab" data-toggle="tab"><%= t('.tabs.banner_image') %></a> + <li class="nav-item"> + <a class="nav-link" href="#banner_image" role="tab" data-toggle="tab"><%= t('.tabs.banner_image') %></a> </li> - <li> - <a href="#directory_image" role="tab" data-toggle="tab"><%= t('.tabs.directory_image') %></a> + <li class="nav-item"> + <a class="nav-link" href="#directory_image" role="tab" data-toggle="tab"><%= t('.tabs.directory_image') %></a> </li> - <li> - <a href="#default_images" role="tab" data-toggle="tab"><%= t('.tabs.default_images') %></a> + <li class="nav-item"> + <a class="nav-link" href="#default_images" role="tab" data-toggle="tab"><%= t('.tabs.default_images') %></a> </li> - <li> - <a href="#color" role="tab" data-toggle="tab"><%= t('.tabs.colors') %></a> + <li class="nav-item"> + <a class="nav-link" href="#color" role="tab" data-toggle="tab"><%= t('.tabs.colors') %></a> </li> - <li> - <a href="#font" role="tab" data-toggle="tab"><%= t('.tabs.fonts') %></a> + <li class="nav-item"> + <a class="nav-link" href="#font" role="tab" data-toggle="tab"><%= t('.tabs.fonts') %></a> </li> - <li> - <a href="#css" role="tab" data-toggle="tab"><%= t('.tabs.custom_css') %></a> + <li class="nav-item"> + <a class="nav-link" href="#css" role="tab" data-toggle="tab"><%= t('.tabs.custom_css') %></a> </li> - <li> - <a href="#themes" role="tab" data-toggle="tab"><%= t('.tabs.themes') %></a> + <li class="nav-item"> + <a class="nav-link" href="#themes" role="tab" data-toggle="tab"><%= t('.tabs.themes') %></a> </li> </ul> <div class="tab-content"> <div id="logo_image" class="tab-pane active"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'logo_image_form' %> </div> </div> <div id="favicon" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'favicon_form' %> </div> </div> <div id="banner_image" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'banner_image_form' %> </div> </div> <div id="directory_image" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'directory_image_form' %> </div> </div> <div id="default_images" class="tab-pane" data-alert="<%= I18n.t('hyrax.admin.appearances.show.forms.default_images.alert') %>"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'default_images_form' %> </div> </div> <div id="color" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'default_colors_form' %> </div> </div> <div id="font" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'default_fonts_form' %> </div> </div> <div id="css" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'custom_css_form' %> </div> </div> <div id="themes" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card"> <%= render 'theme_form' %> </div> </div> diff --git a/app/views/hyrax/admin/collection_types/_form_participants.html.erb b/app/views/hyrax/admin/collection_types/_form_participants.html.erb index 52e3b0658..7e0c7bdc4 100644 --- a/app/views/hyrax/admin/collection_types/_form_participants.html.erb +++ b/app/views/hyrax/admin/collection_types/_form_participants.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 Make group field a select instead of text input %> +<%# OVERRIDE Hyrax v5.0.0rc2 Make group field a select instead of text input %> <h3><%= t('.add_participants') %></h3> <p><%= t('.instructions') %></p> <% access_options = options_for_select([ @@ -14,9 +14,9 @@ html: { id: 'group-participants-form' }, as: :collection_type_participant do |f| %> <div class="form-inline add-participants-form"> - <label class="col-md-2 col-xs-4 control-label"><%= t('.add_group') %>:</label> + <label class="col-md-2 col-4 col-form-label"><%= t('.add_group') %>:</label> - <div class="col-md-10 col-xs-8 form-group"> + <div class="col-md-10 col-8 form-group"> <%= f.hidden_field :hyrax_collection_type_id, value: @collection_type_participant.hyrax_collection_type_id %> <%= f.hidden_field :agent_type, value: Hyrax::CollectionTypeParticipant::GROUP_TYPE %> <%# OVERRIDE: change from text_field to select %> @@ -43,9 +43,9 @@ html: { id: 'user-participants-form' }, as: :collection_type_participant do |f| %> <div class="form-inline add-participants-form"> - <label class="col-md-2 col-xs-4 control-label"><%= t('.add_user') %>:</label> + <label class="col-md-2 col-4 col-form-label"><%= t('.add_user') %>:</label> - <div class="col-md-10 col-xs-8 form-group"> + <div class="col-md-10 col-8 form-group"> <%= f.hidden_field :hyrax_collection_type_id, value: @collection_type_participant.hyrax_collection_type_id %> <%= f.hidden_field :agent_type, value: Hyrax::CollectionTypeParticipant::USER_TYPE %> <%= f.text_field :agent_id, diff --git a/app/views/hyrax/admin/stats/show.html.erb b/app/views/hyrax/admin/stats/show.html.erb index 273caa4a7..4996fe330 100644 --- a/app/views/hyrax/admin/stats/show.html.erb +++ b/app/views/hyrax/admin/stats/show.html.erb @@ -1,21 +1,29 @@ <% content_for :page_header do %> <h1><span class="fa fa-edit"></span> Statistics for <%= application_name %></h1> <% end %> - - <div class="panel panel-default tabs"> + + <div class="card tabs"> <!-- Nav tabs --> <ul id="statistics-tabs" class="nav nav-tabs" role="tablist"> - <li role="presentation" class="active"><a href="#collections" aria-controls="collections" role="tab" data-toggle="tab">Collections</a></li> - <li role="presentation"><a href="#works" aria-controls="works" role="tab" data-toggle="tab">Works</a></li> - <li role="presentation"><a href="#downloads" aria-controls="downloads" role="tab" data-toggle="tab">Downloads</a></li> - <li role="presentation"><a href="#users" aria-controls="users" role="tab" data-toggle="tab">Users</a></li> + <li class="nav-item"> + <a class="nav-link active" href="#collections" role="tab" data-toggle="tab">Collections</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#works" role="tab" data-toggle="tab">Works</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#downloads" role="tab" data-toggle="tab">Downloads</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#users" role="tab" data-toggle="tab">Users</a> + </li> </ul> <!-- Tab panes --> <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="collections"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="tab-pane active" id="collections"> + <div class="card labels"> + <div class="card-body"> <h2>Collections over time</h2> <%= graph_tag('collection-graph', [Hyrax::Statistics::Collections::OverTime.new.points], { @@ -34,8 +42,8 @@ </div> </div> <div role="tabpanel" class="tab-pane" id="works"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="card labels"> + <div class="card-body"> <h2>Works over time</h2> <%= graph_tag('works-graph', [Hyrax::Statistics::Works::OverTime.new.points], { @@ -62,21 +70,20 @@ </div> </div> <div role="tabpanel" class="tab-pane" id="downloads"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="card labels"> + <div class="card-body"> ... </div> </div> </div> <div role="tabpanel" class="tab-pane" id="users"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="card labels"> + <div class="card-body"> <%= render "hyrax/admin/stats/stats_by_date" %> <%= render "hyrax/admin/stats/top_data" %> </div> </div> </div> - </div> <script> Blacklight.onLoad(function() { var stats = require('statistics_tab_manager'); @@ -84,5 +91,5 @@ new stats.Tab('#works'); }); </script> - + </div> </div> diff --git a/app/views/hyrax/admin/users/index.html.erb b/app/views/hyrax/admin/users/index.html.erb index dc12474c7..9d5d33dbe 100644 --- a/app/views/hyrax/admin/users/index.html.erb +++ b/app/views/hyrax/admin/users/index.html.erb @@ -9,14 +9,14 @@ <% end %> <% if can? :create, User %> - <div class="panel panel-default users-invite"> - <div class="panel-heading"> + <div class="card users-invite"> + <div class="card-header"> <%= t('.invite_users') %> </div> - <div class="panel-body"> + <div class="card-body"> <%# user_invitation_path is provided by devise_invitable %> - <%= simple_form_for :user, url: main_app.user_invitation_path, html: { class: 'form-inline pull-left' } do |f| %> + <%= simple_form_for :user, url: main_app.user_invitation_path, html: { class: 'form-inline d-inline-flex' } do |f| %> <div class="form-group"> <%= f.hint :email %> <%= f.label :email, class: "control-label", required: false %> @@ -33,12 +33,12 @@ </div> <% end %> -<div class="panel panel-default users-listing"> - <div class="panel-heading"> +<div class="card users-listing"> + <div class="card-header"> <%= t('hyrax.admin.users.index.describe_users_html', count: @presenter.user_count) %> </div> - <div class="panel-body"> + <div class="card-body"> <div class="table-responsive"> <table class="table table-striped datatable"> <thead> diff --git a/app/views/hyrax/admin/workflow_roles/index.html.erb b/app/views/hyrax/admin/workflow_roles/index.html.erb index 4d642f0ec..1c99b0682 100644 --- a/app/views/hyrax/admin/workflow_roles/index.html.erb +++ b/app/views/hyrax/admin/workflow_roles/index.html.erb @@ -1,19 +1,19 @@ -<%# OVERRIDE Hyrax v3.4.2 Add workflow roles to groups %> +<%# OVERRIDE Hyrax v5.0.0rc2 Add workflow roles to groups %> <% provide :page_header do %> <h1><span class="fa fa-users" aria-hidden="true"></span> <%= t("hyrax.admin.workflow_roles.header") %></h1> <% end %> <div class="row"> <div class="col-md-12"> - <div class="panel panel-default"> - <div class='panel-body'> + <div class="card"> + <div class='card-body'> <%# OVERRIDE: New form for adding workflow roles to groups %> <!-- BEGIN Assign Role to Group --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h2 class='panel-title h2'><%= t('.new_group_role') %></h2> + <div class='card'> + <div class='card-header'> + <h2 class='card-title h2'><%= t('.new_group_role') %></h2> </div> - <div class='panel-body'> + <div class='card-body'> <%= simple_form_for Hyrax::Forms::WorkflowResponsibilityGroupForm.new, url: hyrax.admin_workflow_roles_path, html: { id: :new_sipity_group_workflow_responsibility } do |f| %> <%= f.input :group_id, as: :select, collection: f.object.group_options, label_method: :humanized_name, value_method: :id %> <%= f.input :workflow_role_id, as: :select, collection: f.object.workflow_role_options, input_html: { id: :sipity_workflow_responsibility_group_workflow_role_id } %> @@ -24,11 +24,11 @@ <!-- END Assign Role to Group --> <!-- BEGIN Assign Role to User --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h2 class='panel-title h2'><%= t('.new_user_role') %></h2> + <div class='card'> + <div class='card-header'> + <h2 class='card-title h2'><%= t('.new_user_role') %></h2> </div> - <div class='panel-body'> + <div class='card-body'> <%= simple_form_for Hyrax::Forms::WorkflowResponsibilityForm.new, url: hyrax.admin_workflow_roles_path do |f| %> <%= f.input :user_id, as: :select, collection: f.object.user_options %> <%= f.input :workflow_role_id, as: :select, collection: f.object.workflow_role_options %> @@ -44,15 +44,15 @@ <div class="row"> <div class="col-md-12"> - <div class="panel panel-default"> - <div class='panel-body'> + <div class="card"> + <div class='card-body'> <%# OVERRIDE: Add section for current group roles %> <!-- BEGIN Current Group Roles --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h2 class='panel-title h2'><%= t('.current_group_roles') %></h2> + <div class='card'> + <div class='card-header'> + <h2 class='card-title h2'><%= t('.current_group_roles') %></h2> </div> - <div class='panel-body'> + <div class='card-body'> <table class='table table-striped datatable group-workflow-roles-table'> <thead> <th><%= t('.header.group_name') %></th> @@ -89,11 +89,11 @@ <!-- END Current Group Roles --> <!-- BEGIN Current User Roles --> - <div class='panel panel-default'> - <div class='panel-heading'> - <h2 class='panel-title h2'><%= t('.current_user_roles') %></h2> + <div class='card'> + <div class='card-header'> + <h2 class='card-title h2'><%= t('.current_user_roles') %></h2> </div> - <div class='panel-body'> + <div class='card-body'> <table class='table table-striped datatable user-workflow-roles-table'> <thead> <th><%= t('.header.email') %></th> diff --git a/app/views/hyrax/base/_form_share.html.erb b/app/views/hyrax/base/_form_share.html.erb index 732cbe199..b9988386e 100644 --- a/app/views/hyrax/base/_form_share.html.erb +++ b/app/views/hyrax/base/_form_share.html.erb @@ -1,7 +1,7 @@ -<%# OVERRIDE: Hyrax 2.5.1 to use Hyrax::Groups for groups select box %> +<%# OVERRIDE: Hyrax v5.0.0rc2 to use Hyrax::Groups for groups select box %> <p><%= t('.directions') %></p> -<h2><%= t('.add_sharing') %></h2> +<h2 class="h3 mt-4"><%= t('.add_sharing') %></h2> <% depositor = f.object.depositor %> @@ -29,7 +29,7 @@ <label for="new_group_permission_skel" class="sr-only">Access type to grant</label> <%= select_tag 'new_group_permission_skel', options_for_select(Hyrax.config.permission_options), class: 'form-control' %> - <button class="btn btn-default" id="add_new_group_skel"> + <button class="btn btn-secondary ml-2" id="add_new_group_skel"> <span>Add<span class="sr-only"> this group</span></span> </button> <br /><span id="directory_group_result"></span> @@ -45,7 +45,7 @@ <%= text_field_tag 'new_user_name_skel', nil %> <label for="new_user_permission_skel" class="sr-only">Access type to grant</label> <%= select_tag 'new_user_permission_skel', options_for_select(Hyrax.config.permission_options), class: 'form-control' %> - <button class="btn btn-default" id="add_new_user_skel"> + <button class="btn btn-secondary ml-2" id="add_new_user_skel"> <span>Add<span class="sr-only"> this <%= t('hyrax.account_label') %></span></span> </button> <br /> <span id="directory_user_result"></span> diff --git a/app/views/hyrax/base/_show_actions.html.erb b/app/views/hyrax/base/_show_actions.html.erb index b726f7dba..07151faa2 100644 --- a/app/views/hyrax/base/_show_actions.html.erb +++ b/app/views/hyrax/base/_show_actions.html.erb @@ -1,21 +1,21 @@ -<%# OVERRIDE Hyrax v3.4.2 Adjust permission checks and add analytics button %> +<%# OVERRIDE Hyrax v5.0.0rc2 Adjust permission checks and add analytics button %> <div class="show-actions"> <% if presenter.editor? %> - <%= link_to "Edit", edit_polymorphic_path([main_app, presenter]), class: 'btn btn-default' %> + <%= link_to t('.edit'), edit_polymorphic_path([main_app, presenter]), class: 'btn btn-secondary' %> <%# OVERRIDE: wrap Delete button in #can? check %> <% if current_ability.can?(:delete, presenter.solr_document) %> <%= link_to "Delete", [main_app, presenter], class: 'btn btn-danger', data: { confirm: "Delete this #{presenter.human_readable_type}?" }, method: :delete %> <% end %> <% if presenter.member_presenters.size > 1 %> - <%= link_to t("hyrax.file_manager.link_text"), polymorphic_path([main_app, :file_manager, presenter]), class: 'btn btn-default' %> + <%= link_to t("hyrax.file_manager.link_text"), polymorphic_path([main_app, :file_manager, presenter]), class: 'btn btn-secondary' %> <% end %> <% if presenter.valid_child_concerns.length > 0 %> <div class="btn-group"> - <button type="button" class="btn btn-default dropdown-toggle" type="button" id="dropdown-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + <button type="button" class="btn btn-secondary dropdown-toggle" type="button" id="dropdown-menu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Attach Child <span class="caret"></span></button> <ul class="dropdown-menu"> <% presenter.valid_child_concerns.each do |concern| %> - <li> + <li class="dropdown-item"> <%= link_to "Attach #{concern.human_readable_type}", polymorphic_path([main_app, :new, :hyrax, :parent, concern.model_name.singular.to_sym], parent_id: presenter.id) %> </li> <% end %> @@ -26,22 +26,22 @@ <% if presenter.show_deposit_for?(collections: @user_collections) %> <input type="checkbox" style="display:none" name="batch_document_ids[]" id="batch_document_<%= presenter.id %>" value="<%= presenter.id %>" class="batch_document_selector" checked="checked" /> <%= button_tag t('hyrax.dashboard.my.action.add_to_collection'), - class: 'btn btn-default submits-batches submits-batches-add', + class: 'btn btn-secondary submits-batches submits-batches-add', data: { toggle: "modal", target: "#collection-list-container" } %> <% end %> <% if presenter.work_featurable? %> <%= link_to "Feature", hyrax.featured_work_path(presenter, format: :json), data: { behavior: 'feature' }, - class: presenter.display_unfeature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + class: presenter.display_unfeature_link? ? 'btn btn-secondary collapse' : 'btn btn-secondary' %> <%= link_to "Unfeature", hyrax.featured_work_path(presenter, format: :json), data: { behavior: 'unfeature' }, - class: presenter.display_feature_link? ? 'btn btn-default collapse' : 'btn btn-default' %> + class: presenter.display_feature_link? ? 'btn btn-secondary collapse' : 'btn btn-secondary' %> <% end %> <% if Hyrax.config.analytics? %> <% # turbolinks needs to be turned off or the page will use the cache and the %> <% # analytics graph will not show unless the page is refreshed. %> - <%= link_to t('.analytics'), presenter.stats_path, id: 'stats', class: 'btn btn-default', data: { turbolinks: false } %> + <%= link_to t('.analytics'), presenter.stats_path, id: 'stats', class: 'btn btn-secondary', data: { turbolinks: false } %> <% end %> </div> diff --git a/app/views/hyrax/base/show.html.erb b/app/views/hyrax/base/show.html.erb index 01ccf18ca..47e5b202f 100644 --- a/app/views/hyrax/base/show.html.erb +++ b/app/views/hyrax/base/show.html.erb @@ -8,11 +8,11 @@ <div class="col-sm-12"> <%= render 'work_type', presenter: @presenter %> </div> - <div itemscope itemtype="http://schema.org/CreativeWork" class="col-xs-12"> + <div itemscope itemtype="http://schema.org/CreativeWork" class="col-12"> <%= render 'work_title', presenter: @presenter %> <%= render 'show_actions', presenter: @presenter %> - <div class="panel panel-default"> - <div class="panel-body"> + <div class="card"> + <div class="card-body"> <div class="row"> <%= render 'workflow_actions_widget', presenter: @presenter %> <% if @presenter.iiif_viewer? %> @@ -31,22 +31,22 @@ </div> </div> </div> - </div><!-- /panel --> + </div><!-- /card --> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><%= t('hyrax.base.show.relationships') %></h1> + <div class="card"> + <div class="card-header"> + <h2 class="card-title"><%= t('hyrax.base.show.relationships') %></h2> </div> - <div class="panel-body"> + <div class="card-body"> <%= render 'relationships', presenter: @presenter %> </div> </div> - <div class="panel panel-default"> - <div class="panel-heading"> - <h1 class="panel-title"><%= t('.items') %></h1> + <div class="card"> + <div class="card-header"> + <h2 class="card-title"><%= t('.items') %></h2> </div> - <div class="panel-body"> + <div class="card-body"> <%= render 'items', presenter: @presenter %> </div> </div> diff --git a/app/views/hyrax/contact_form/new.html.erb b/app/views/hyrax/contact_form/new.html.erb index 18ddba15c..b1c6d774c 100644 --- a/app/views/hyrax/contact_form/new.html.erb +++ b/app/views/hyrax/contact_form/new.html.erb @@ -1,4 +1,4 @@ -<%# Hyrax 3.4.2 override to add negative captcha %> +<%# OVERRIDE Hyrax v5.0.0rc2 override to add negative captcha %> <% provide :page_title, I18n.t('hyrax.contact_form.title') %> <div class="alert alert-info"> @@ -17,36 +17,36 @@ <% em = '' %> <% end %> -<%= form_for @contact_form, url: hyrax.contact_form_index_path, - html: { class: 'form-horizontal' } do |f| %> +<%= form_for @contact_form, url: hyrax.contact_form_index_path, html: { class: 'needs-validation' } do |f| %> <%= raw negative_captcha(@captcha) %> - <%= f.text_field :contact_method, class: 'hide' %> - <div class="form-group"> - <%= f.label :category, t('hyrax.contact_form.type_label'), class: "col-sm-2 control-label" %> + <%= f.text_field :contact_method, class: 'd-none' %> + + <div class="form-group row"> + <%= f.label :category, t('hyrax.contact_form.type_label'), class: "col-sm-2 col-form-label" %> <div class="col-sm-10"> <%= f.select 'category', options_for_select(contact_form_issue_type_options), { include_blank: t('hyrax.contact_form.select_type') }, {class: 'form-control', required: true } %> </div> </div> - <div class="form-group"> - <%= negative_label_tag(@captcha, :name, t('hyrax.contact_form.name_label'), class: "col-sm-2 control-label" ) %> - <div class="col-sm-10"><%= negative_text_field_tag(@captcha, :name, value: nm, class: 'form-control', required: true ) %></div> + <div class="form-group row"> + <%= negative_label_tag(@captcha, :name, t('hyrax.contact_form.name_label'), class: "col-sm-2 col-form-label") %> + <div class="col-sm-10"><%= negative_text_field_tag(@captcha, :name, value: nm, class: 'form-control', required: true) %></div> </div> - <div class="form-group"> - <%= negative_label_tag(@captcha, :email, t('hyrax.contact_form.email_label'), class: "col-sm-2 control-label" ) %> - <div class="col-sm-10"><%= negative_text_field_tag(@captcha, :email, value: em, class: 'form-control', required: true ) %></div> + <div class="form-group row"> + <%= negative_label_tag(@captcha, :email, t('hyrax.contact_form.email_label'), class: "col-sm-2 col-form-label") %> + <div class="col-sm-10"><%= negative_text_field_tag(@captcha, :email, value: em, class: 'form-control', required: true) %></div> </div> - <div class="form-group"> - <%= f.label :subject, t('hyrax.contact_form.subject_label'), class: "col-sm-2 control-label" %> + <div class="form-group row"> + <%= f.label :subject, t('hyrax.contact_form.subject_label'), class: "col-sm-2 col-form-label" %> <div class="col-sm-10"><%= f.text_field :subject, class: 'form-control', required: true %></div> </div> - <div class="form-group"> - <%= negative_label_tag(@captcha, :message, t('hyrax.contact_form.message_label'), class: "col-sm-2 control-label" ) %> - <div class="col-sm-10"><%= negative_text_area_tag(@captcha, :message, rows: 4, class: 'form-control', required: true ) %></div> + <div class="form-group row"> + <%= negative_label_tag(@captcha, :message, t('hyrax.contact_form.message_label'), class: "col-sm-2 col-form-label") %> + <div class="col-sm-10"><%= negative_text_area_tag(@captcha, :message, rows: 4, class: 'form-control', required: true) %></div> </div> <%= f.submit value: t('hyrax.contact_form.button_label'), class: "btn btn-primary" %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/content_blocks/_form.html.erb b/app/views/hyrax/content_blocks/_form.html.erb index ccf22f70f..e9375879d 100644 --- a/app/views/hyrax/content_blocks/_form.html.erb +++ b/app/views/hyrax/content_blocks/_form.html.erb @@ -1,26 +1,44 @@ -<%# Copied from Hyrax v2.9.0 to add home_text content block form - Adding themes %> +<%# Copied from Hyrax v5.0.0rc2 to add home_text content block form - Adding themes %> <%# imported from hyrax 3.0.0.pre.rc1 %> <%= render "shared/nav_safety_modal" %> -<div class="panel panel-default tabs"> +<div class="card tabs"> <ul class="nav nav-tabs" role="tablist"> - <li class="active"> - <a href="#announcement_text" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t(:'hyrax.content_blocks.tabs.announcement_text') %></a> + <li id="announcement-nav-item" class="nav-item"> + <a href="#announcement_text" role="tab" data-toggle="tab" class="nav-link active nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.announcement_text') %> + </a> </li> - <li> - <a href="#marketing" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t(:'hyrax.content_blocks.tabs.marketing_text') %></a> + <li id="marketing-nav-item" class="nav-item"> + <a href="#marketing" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.marketing_text') %> + </a> </li> - <li> - <a href="#home_text" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t(:'hyrax.content_blocks.tabs.home_text') %></a> + <li id="home-text-nav-item" class="nav-item"> + <a href="#home_text" role="tab" data-toggle="tab" class="nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.home_text') %> + </a> </li> - <li> - <a href="#researcher" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t(:'hyrax.content_blocks.tabs.featured_researcher') %></a> + <li id="researcher-nav-item" class="nav-item"> + <a href="#researcher" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.featured_researcher') %> + </a> + </li> + <li id="homepage-about-heading-nav-item" class="nav-item"> + <a href="#homepage_about_section_heading" role="tab" data-toggle="tab" class="nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.homepage_about_section_heading') %> + </a> + </li> + <li id="homepage-about-content-nav-item" class="nav-item"> + <a href="#homepage_about_section_content" role="tab" data-toggle="tab" class="nav-safety-confirm"> + <%= t(:'hyrax.content_blocks.tabs.homepage_about_section_content') %> + </a> </li> </ul> <div class="tab-content"> - <div id="announcement_text" class="tab-pane active"> - <div class="panel panel-default labels"> + <div id="announcement_text" class="tab-pane show active"> + <div class="card labels"> <%= simple_form_for ContentBlock.for(:announcement), url: hyrax.content_block_path(ContentBlock.for(:announcement)), html: {class: 'nav-safety'} do |f| %> - <div class="panel-body"> + <div class="card-body"> <div class="field form-group"> <%= f.label :announcement %><br /> <%# the following line was changed from hyrax to give some context for what this context block does %> @@ -28,17 +46,17 @@ <%= f.text_area :announcement, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> </div> </div> - <div class="panel-footer"> - <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-default pull-right' %> - <%= f.button :submit, class: 'btn btn-primary pull-right' %> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> </div> <% end %> </div> </div> <div id="marketing" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card labels"> <%= simple_form_for ContentBlock.for(:marketing), url: hyrax.content_block_path(ContentBlock.for(:marketing)), html: {class: 'nav-safety'} do |f| %> - <div class="panel-body"> + <div class="card-body"> <div class="field form-group"> <%= f.label :marketing %><br /> <%# the following line was changed from hyrax to give some context for what this context block does %> @@ -46,18 +64,18 @@ <%= f.text_area :marketing, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> </div> </div> - <div class="panel-footer"> - <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-default pull-right' %> - <%= f.button :submit, class: 'btn btn-primary pull-right' %> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> </div> <% end %> </div> </div> <%# Copied from Hyrax v2.9.0 to add home_text content block form - Adding themes %> <div id="home_text" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card labels"> <%= simple_form_for ContentBlock.for(:home_text), url: hyrax.content_block_path(ContentBlock.for(:home_text)), html: {class: 'nav-safety'} do |f| %> - <div class="panel-body"> + <div class="card-body"> <div class="field form-group"> <%= f.label :home_text %><br /> <%# the following line was added to hyku for home page text for themes that use or allow home page text %> @@ -65,17 +83,17 @@ <%= f.text_area :home_text, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> </div> </div> - <div class="panel-footer"> - <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-default pull-right' %> - <%= f.button :submit, class: 'btn btn-primary pull-right' %> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> </div> <% end %> </div> </div> <div id="researcher" class="tab-pane"> - <div class="panel panel-default labels"> + <div class="card labels"> <%= simple_form_for ContentBlock.for(:researcher), url: hyrax.content_block_path(ContentBlock.for(:researcher)), html: {class: 'nav-safety'} do |f| %> - <div class="panel-body"> + <div class="card-body"> <div class="field form-group"> <%= f.label :researcher %><br /> <%# the following line was changed from hyrax to give some context for what this context block does %> @@ -83,9 +101,45 @@ <%= f.text_area :researcher, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> </div> </div> - <div class="panel-footer"> - <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-default pull-right' %> - <%= f.button :submit, class: 'btn btn-primary pull-right' %> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> + </div> + <% end %> + </div> + </div> + <div id="homepage_about_section_heading" class="tab-pane"> + <div class="card labels"> + <%= simple_form_for ContentBlock.for(:homepage_about_section_heading), url: hyrax.content_block_path(ContentBlock.for(:homepage_about_section_heading)), html: {class: 'nav-safety'} do |f| %> + <div class="card-body"> + <div class="field form-group"> + <%= f.label :homepage_about_section_heading %><br /> + <%# the following line was changed from hyrax to give some context for what this context block does %> + <p class="content-block-instructions"><%= t(:'hyrax.content_blocks.instructions.homepage_about_section_heading_instructions') %></p> + <%= f.text_area :homepage_about_section_heading, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> + </div> + </div> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> + </div> + <% end %> + </div> + </div> + <div id="homepage_about_section_content" class="tab-pane"> + <div class="card labels"> + <%= simple_form_for ContentBlock.for(:homepage_about_section_content), url: hyrax.content_block_path(ContentBlock.for(:homepage_about_section_content)), html: {class: 'nav-safety'} do |f| %> + <div class="card-body"> + <div class="field form-group"> + <%= f.label :homepage_about_section_content %><br /> + <%# the following line was changed from hyrax to give some context for what this context block does %> + <p class="content-block-instructions"><%= t(:'hyrax.content_blocks.instructions.homepage_about_section_content_instructions') %></p> + <%= f.text_area :homepage_about_section_content, value: f.object.value, class: 'form-control tinymce', rows: 20, cols: 120 %> + </div> + </div> + <div class="card-footer d-flex justify-content-end"> + <%= f.button :submit, class: 'btn btn-primary text-white mr-2' %> + <%= link_to t(:'hyrax.content_blocks.cancel'), hyrax.admin_admin_sets_path, class: 'btn btn-light' %> </div> <% end %> </div> diff --git a/app/views/hyrax/dashboard/_sidebar.html.erb b/app/views/hyrax/dashboard/_sidebar.html.erb index c91d9f0f4..4e9797e94 100644 --- a/app/views/hyrax/dashboard/_sidebar.html.erb +++ b/app/views/hyrax/dashboard/_sidebar.html.erb @@ -1,8 +1,10 @@ +<%# OVERIDE Hyrax v5.0.0rc2 to use Hyku::MenuPresenter and add title attribute to link %> + <% menu = Hyku::MenuPresenter.new(self) %> <div class="sidebar-toggle"><span class="fa fa-chevron-circle-right"></span></div> <nav aria-label="sidebar-nav"> - <ul class="nav nav-pills nav-stacked"> - <li> + <ul class="nav nav-pills flex-column"> + <li class="nav-item"> <div class="profile"> <div class="profile-image"> <%= image_tag current_user.avatar.url(:thumb), width: 100 if current_user.avatar.present? %> @@ -12,8 +14,10 @@ </div> </div> </li> - <li> - <%= link_to hyrax.dashboard_path, title: t('hyrax.admin.sidebar.dashboard') do %> + <li class="nav-item"> + <%= link_to hyrax.dashboard_path, + class: "nav-link", + title: t('hyrax.admin.sidebar.dashboard') do %> <span class="fa fa-home" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.dashboard') %></span> <% end %> </li> diff --git a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb index 33306d375..7c78b27a4 100644 --- a/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb +++ b/app/views/hyrax/dashboard/collections/_current_thumbnail.html.erb @@ -1,5 +1,5 @@ <% thumbnail_path = SolrDocument.find(@collection.id).thumbnail_path %> - <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Rails.root.join("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> + <% if thumbnail_path.include?("uploaded_collection_thumbnails") and File.exist? Hyku::Application.path_for("public#{::SolrDocument.find(@collection.id).thumbnail_path}") %> <%= image_tag(thumbnail_path, class: "current-thumbnail") %> <p>Current image: <strong><%= @thumbnail_filename %></strong></p> <% else %> diff --git a/app/views/hyrax/dashboard/collections/_form.html.erb b/app/views/hyrax/dashboard/collections/_form.html.erb index 6915e4590..23a8a1681 100644 --- a/app/views/hyrax/dashboard/collections/_form.html.erb +++ b/app/views/hyrax/dashboard/collections/_form.html.erb @@ -1,34 +1,42 @@ -<%# OVERRIDE Hyrax 2.9.1 to make it say 'Default thumbnail' in the thumbnail select box instead of 'undefined' %> +<%# OVERRIDE Hyrax v5.0.0rc2 to make it say 'Default thumbnail' in the thumbnail select box instead of 'undefined' %> <%= render "shared/nav_safety_modal" %> -<div class="panel panel-default tabs" id="collection-edit-controls"> - <ul class="nav nav-tabs" role="tablist"> - <li class="active"> - <a href="#description" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t('.tabs.description') %></a> +<div class="tabs mt-4" id="collection-edit-controls"> + <ul class="nav nav-tabs" id="dashboard-collection-tab" role="tablist"> + <li class="nav-item"> + <a href="#description" role="tab" data-toggle="tab" class="nav-link active nav-safety-confirm"> + <%= t('.tabs.description') %> + </a> </li> <% if @form.persisted? %> <% if collection_brandable?(collection: @collection) %> - <li> - <a href="#branding" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t('.tabs.branding') %></a> + <li class="nav-item"> + <a href="#branding" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"> + <%= t('.tabs.branding') %> + </a> </li> <% end %> <% if collection_discoverable?(collection: @collection) %> - <li> - <a href="#discovery" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t('.tabs.discovery') %></a> + <li class="nav-item"> + <a href="#discovery" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"> + <%= t('.tabs.discovery') %> + </a> </li> <% end %> <% if collection_sharable?(collection: @collection) %> - <li> - <a href="#sharing" role="tab" data-toggle="tab" class="nav-safety-confirm"><%= t('.tabs.sharing') %></a> + <li class="nav-item"> + <a href="#sharing" role="tab" data-toggle="tab" class="nav-link nav-safety-confirm"> + <%= t('.tabs.sharing') %> + </a> </li> <% end %> <% end %> </ul> <%= simple_form_for @form, url: [hyrax, :dashboard, @form], html: { class: 'editor nav-safety', data: { behavior: 'collection-form', 'param-key' => @form.model_name.param_key } } do |f| %> - <div class="tab-content"> - <div id="description" class="tab-pane active"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="tab-content card" id="dashboard-collection-tab-content"> + <div id="description" class="tab-pane show active"> + <div class="labels"> + <div class="card-body"> <div id="base-terms"> <% f.object.primary_terms.each do |term| %> @@ -58,7 +66,7 @@ <% if f.object.display_additional_fields? %> <%= link_to t('hyrax.collection.form.additional_fields'), '#extended-terms', - class: 'btn btn-default additional-fields', + class: 'btn btn-secondary additional-fields', data: { toggle: 'collapse' }, role: "button", 'aria-expanded'=> "false", @@ -88,8 +96,8 @@ <% if @form.persisted? %> <% if collection_brandable?(collection: @collection) %> <div id="branding" class="tab-pane"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="card labels"> + <div class="card-body"> <%= render 'form_branding', f: f %> </div> </div> @@ -98,8 +106,8 @@ <% if collection_discoverable?(collection: @collection) %> <div id="discovery" class="tab-pane"> - <div class="panel panel-default labels"> - <div class="panel-body"> + <div class="card labels"> + <div class="card-body"> <%= render 'form_discovery', f: f %> </div> </div> @@ -108,8 +116,8 @@ <% if collection_sharable?(collection: @collection) %> <div id="sharing" class="tab-pane"> - <div class="panel panel-default labels" id="collection_permissions" data-param-key="<%= f.object.model_name.param_key %>"> - <div class="panel-body"> + <div class="card labels" id="collection_permissions" data-param-key="<%= f.object.model_name.param_key %>"> + <div class="card-body"> <%= render 'form_share', f: f %> </div> </div> @@ -117,7 +125,7 @@ <% end %> <% end %> - <div class="panel-footer"> + <div class="card-footer"> <% if @collection.persisted? %> <%= f.submit t(:'hyrax.collection.select_form.update'), class: 'btn btn-primary', onclick: "confirmation_needed = false;", id: "update_submit", name: "update_collection" %> <%= link_to t(:'helpers.action.cancel'), hyrax.dashboard_collection_path(@collection), class: 'btn btn-link' %> diff --git a/app/views/hyrax/dashboard/collections/_form_branding.html.erb b/app/views/hyrax/dashboard/collections/_form_branding.html.erb index 38bf18487..14df747e2 100644 --- a/app/views/hyrax/dashboard/collections/_form_branding.html.erb +++ b/app/views/hyrax/dashboard/collections/_form_branding.html.erb @@ -1,4 +1,4 @@ - <!-- OVERRIDE Hyrax v3.4.1 to add text for collection banner image + <!-- OVERRIDE Hyrax v5.0.0rc2 to add text for collection banner image also added image tags to show logo images... js templates branding to show them seems to be broken uses Hyrax::Forms::CollectionForm --> @@ -15,29 +15,30 @@ <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --> <div class="row fileupload-buttonbar"> - <div class="col-sm-3"> + <div class="col-4"> <!-- The fileinput-button span is used to style the file input field as button --> <span class="btn btn-success fileinput-button"> - <span class="glyphicon glyphicon-plus"></span> + <span class="fa fa-plus"></span> <span><%= t('.choose_file') %></span> <input type="file" name="files[]" single /> </span> - </div> <!-- end col-xs-4 --> + </div> <!-- end col-4 --> <!-- The global progress state --> - <div class="col-xs-8 fileupload-progress branding-banner-progress fade"> + <div class="col-8 fileupload-progress branding-banner-progress fade"> <!-- The global progress bar --> - <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"> - <div class="progress-bar progress-bar-success" style="width:0%;"></div> + <div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"> + <div class="progress-bar progress-bar-striped progress-bar-animated bg-success" style="width:0%;"></div> </div> <!-- The extended global progress state --> <div class="progress-extended"> </div> - </div> <!-- end col-xs-5 fileupload-progress fade --> + </div> <!-- end col-8 fileupload-progress fade --> </div> <!-- end row fileupload-buttonbar --> <div class="row branding-banner-list"> - <div class="col-xs-12"> + <div class="col-12"> <div class="container"> + <%# Where the request to display the branding comes from. %> <% if f.object.banner_info[:file] %> <div id="banner"> <div class="row branding-banner-row"> @@ -55,7 +56,7 @@ <div class="col-sm-2"> <button class="btn btn-danger delete branding-banner-remove" data-type="DELETE" data-url="/" onclick=$("#banner").remove();> - <span class="glyphicon glyphicon-remove"></span> + <span class="fa fa-times"></span> <span class="controls-remove-text"><%= t('.remove') %></span> <span class="sr-only"> <%= t('.previous') %> @@ -68,7 +69,7 @@ <% if f.object.banner_info[:relative_path] %> <div class="banner-image"> <i><%= image_tag(f.object.banner_info[:relative_path], - height: "100", + size: "800x100", alt: f.object.banner_info[:alttext].presence || f.object.banner_info[:file]) %></i> </div> <% end %> @@ -97,28 +98,28 @@ <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --> <div class="row fileupload-buttonbar"> - <div class="col-xs-4"> + <div class="col-4"> <!-- The fileinput-button span is used to style the file input field as button --> <span class="btn btn-success fileinput-button"> - <span class="glyphicon glyphicon-plus"></span> + <span class="fa fa-plus"></span> <span><%= t('.choose_file') %></span> <input type="file" name="files[]" single /> </span> - </div> <!-- end col-xs-4 --> + </div> <!-- end col-4 --> <!-- The global progress state --> - <div class="col-xs-8 fileupload-progress branding-logo-progress fade"> + <div class="col-8 fileupload-progress branding-logo-progress fade"> <!-- The global progress bar --> - <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"> - <div class="progress-bar progress-bar-success" style="width:0%;"></div> + <div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"> + <div class="progress-bar progress-bar-striped progress-bar-animated bg-success" style="width:0%;"></div> </div> <!-- The extended global progress state --> <div class="progress-extended"> </div> - </div> <!-- end col-xs-8 fileupload-progress branding-logo-progress fade --> + </div> <!-- end col-8 fileupload-progress branding-logo-progress fade --> </div> <!-- end row fileupload-buttonbar --> <div class="row branding-logo-list"> - <div class="col-xs-12"> + <div class="col-12"> <div class="container"> <% i = 0 %> <% f.object.logo_info.each_with_index do |linfo, i| %> @@ -144,7 +145,7 @@ <div class="col-sm-2"> <button class="btn btn-danger delete branding-logo-remove" data-type="DELETE" data-url="/" onclick=$("#logorow_<%= i %>").remove();> - <span class="glyphicon glyphicon-remove"></span> + <span class="fa fa-times"></span> <span class="controls-remove-text"><%= t('.remove') %></span> <span class="sr-only"> <%= t('.previous') %> @@ -159,7 +160,7 @@ <!-- The global file processing state --> <span class="fileupload-process"></span> - </div> <!-- end col-xs-12 --> + </div> <!-- end col-12 --> </div> <!-- end row branding-logo-list --> </div> <!-- end fileuploadlogo --> -</div> <!-- end set-access-controls --> \ No newline at end of file +</div> <!-- end set-access-controls --> diff --git a/app/views/hyrax/dashboard/collections/_form_discovery.html.erb b/app/views/hyrax/dashboard/collections/_form_discovery.html.erb index 5225832e6..2163c824f 100644 --- a/app/views/hyrax/dashboard/collections/_form_discovery.html.erb +++ b/app/views/hyrax/dashboard/collections/_form_discovery.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 +<%# OVERRIDE Hyrax v5.0.0rc2 - Handle new :manage_discovery ability - Reformat input tags for legibility %> @@ -9,55 +9,64 @@ <%# OVERRIDE: add conditional title %> <div class="form-group" <% if cannot?(:manage_discovery, @collection) %>title="<%= t('permissions.collections.cannot.manage_discovery') %>"<% end %>> - <label class="radio"> + <div class="custom-control custom-radio"> <input type="radio" id="visibility_open" name="<%= f.object_name %>[visibility]" value="<%= Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC %>" + class="custom-control-input" <% if @collection.open_access? %> - checked="true" + checked="checked" <% end %> <%# OVERRIDE: add conditional disable %> <% if cannot?(:manage_discovery, @collection) %> disabled="disabled" <% end %> /> - <strong><%= t('hyrax.visibility.open.text') %></strong> - <%= t('hyrax.visibility.open.note_html') %> - </label> + <label class="custom-control-label" for="visibility_open"> + <strong><%= t('hyrax.visibility.open.text') %></strong> - <%= t('hyrax.visibility.open.note_html') %> + </label> + </div> - <label class="radio"> + <div class="custom-control custom-radio"> <input type="radio" id="visibility_registered" name="<%= f.object_name %>[visibility]" value="<%= Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED %>" + class="custom-control-input" <% if @collection.authenticated_only_access? %> - checked="true" + checked="checked" <% end %> <%# OVERRIDE: add conditional disable %> <% if cannot?(:manage_discovery, @collection) %> disabled="disabled" <% end %> /> - <strong><%= t('hyrax.visibility.authenticated.text', institution: institution_name) %></strong> - <%= t('hyrax.visibility.authenticated.note_html', institution: institution_name) %> - </label> + <label class="custom-control-label" for="visibility_registered"> + <strong><%= t('hyrax.visibility.authenticated.text', institution: institution_name) %></strong> - <%= t('hyrax.visibility.authenticated.note_html', institution: institution_name) %> + </label> + </div> - <label class="radio"> + <div class="custom-control custom-radio"> <input type="radio" id="visibility_restricted" name="<%= f.object_name %>[visibility]" value="<%= Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE %>" + class="custom-control-input" <% if @collection.private_access? %> - checked="true" + checked="checked" <% end %> <%# OVERRIDE: add conditional disable %> <% if cannot?(:manage_discovery, @collection) %> disabled="disabled" <% end %> /> - <strong><%= t('hyrax.visibility.restricted.text') %></strong>- <%= t('hyrax.visibility.restricted.note_html') %> - </label> + <label class="custom-control-label" for="visibility_restricted"> + <strong><%= t('hyrax.visibility.restricted.text') %></strong> - <%= t('hyrax.visibility.restricted.note_html') %> + </label> + </div> </div> </div> diff --git a/app/views/hyrax/dashboard/collections/_form_share.html.erb b/app/views/hyrax/dashboard/collections/_form_share.html.erb index f5671e8fb..0d9cf722b 100644 --- a/app/views/hyrax/dashboard/collections/_form_share.html.erb +++ b/app/views/hyrax/dashboard/collections/_form_share.html.erb @@ -1,91 +1,90 @@ -<%# OVERRIDE Hyrax v3.4.2 Use Hyrax::Groups for groups select box %> +<%# OVERRIDE Hyrax v5.0.0rc2 Use Hyrax::Groups for groups select box %> <% access_options = options_for_select([ - [t('hyrax.dashboard.collections.form_share.access_options.manager'), 'manage'], - [t('hyrax.dashboard.collections.form_share.access_options.depositor'), 'deposit'], - [t('hyrax.dashboard.collections.form_share.access_options.viewer'), 'view']]) %> + [t('hyrax.dashboard.collections.form_share.access_options.manager'), t('manage')], + [t('hyrax.dashboard.collections.form_share.access_options.depositor'), t('deposit')], + [t('hyrax.dashboard.collections.form_share.access_options.viewer'), t('view')]]) %> <div id="participants" class="tab-pane"> - <div class="panel panel-default labels edit-sharing-tab"> - <div class="panel-body"> + <div class="edit-sharing-tab"> + <section class="section-add-sharing"> + <p><%= t('.note') %></p> + <h3><%= t('.add_sharing') %></h3> - <section class="section-add-sharing"> - <p><%= t('.note') %></p> - <h3><%= t('.add_sharing') %></h3> + <!-- Add group form --> + <div class="form-add-sharing-wrapper" data-id="<%= @form.id %>"> + <%= simple_form_for collection_permission_template_form_for(form: @form), + url: [hyrax, :dashboard, @form, :permission_template], + html: { id: 'group-participants-form' } do |f| %> - <!-- Add group form --> - <div class="form-add-sharing-wrapper" data-id="<%= @form.id %>"> - <%= simple_form_for @form.permission_template, - url: [hyrax, :dashboard, @form, :permission_template], - html: { id: 'group-participants-form' } do |f| %> - <div class="clearfix spacer"> - <%= f.fields_for 'access_grants_attributes', - f.object.access_grants.build(agent_type: 'group'), - index: 0 do |builder| %> + <div class="form-inline add-sharing-form sharing-row-form"> + <%= f.fields_for 'access_grants_attributes', + f.object.access_grants.build(agent_type: 'group'), + index: 0 do |builder| %> - <div class="form-inline add-sharing-form"> - <label class="col-md-2 col-xs-4 control-label"><%= t('.add_group') %>:</label> - <div class="col-md-10 col-xs-8 form-group"> - <%= builder.hidden_field :agent_type %> + <div class="form-group mr-2"> + <label class="mr-2"><%= t('.add_group') %>:</label> + <%= builder.hidden_field :agent_type %> + <%= builder.text_field :agent_id, + placeholder: t('.search_for_a_group'), + class: 'form-control search-input' %> + </div> + <div class="form-group"> + <label class="mr-2">as</label> <%# OVERRIDE: Change select to use Hyrax::Groups %> <%= builder.select :agent_id, Hyrax::Group.all.map { |g| [g.humanized_name, g.name] }, - { prompt: "Select a group..." }, + { prompt: t('.select_a_group') }, class: 'form-control' %> - as - <%= builder.select :access, - access_options, - { prompt: "Select a role..." }, - class: 'form-control' %> - - <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info edit-collection-add-sharing-button', :disabled => true %> - </div> - </div> - <% end %> - </div> - <% end %> - </div> + </div> + <% end %> + <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info edit-collection-add-sharing-button ml-2', :disabled => true %> - <!-- Add user form --> - <div class="form-add-sharing-wrapper" data-id="<%= @form.id %>"> - <%= simple_form_for @form.permission_template, - url: [hyrax, :dashboard, @form, :permission_template], - html: { id: 'user-participants-form' } do |f| %> - <div class="clearfix spacer"> + </div><!-- /.form-inline --> + <% end %> + </div> - <%= f.fields_for 'access_grants_attributes', - f.object.access_grants.build(agent_type: 'user'), - index: 0 do |builder| %> + <!-- Add user form --> + <div class="form-add-sharing-wrapper" data-id="<%= @form.id %>"> + <%= simple_form_for collection_permission_template_form_for(form: @form), + url: [hyrax, :dashboard, @form, :permission_template], + html: { id: 'user-participants-form' } do |f| %> - <div class="form-inline add-users"> - <label class="col-md-2 col-xs-4 control-label"><%= t('.add_user') %>:</label> - <div class="col-md-10 col-xs-8 form-group"> - <%= builder.hidden_field :agent_type %> - <%= builder.text_field :agent_id, - placeholder: "Search for a user..." %> - as - <%= builder.select :access, - access_options, - { prompt: "Select a role..." }, - class: 'form-control' %> + <div class="form-inline sharing-row-form add-users"> + <%= f.fields_for 'access_grants_attributes', + f.object.access_grants.build(agent_type: 'user'), + index: 0 do |builder| %> - <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info edit-collection-add-sharing-button', :disabled => true %> - </div> + <div class="form-group"> + <label class="mr-2"><%= t('.add_user') %>:</label> + <%= builder.hidden_field :agent_type %> + <%= builder.text_field :agent_id, + placeholder: t('.search_for_a_user') %> + </div> + <div class="form-group"> + <label class="mx-2">as</label> + <%= builder.select :access, + access_options, + { prompt: t('.select_a_role') }, + class: 'form-control' %> </div> - <% end %> - </div> - <% end %> - </div> + <% end %> + + <%= f.submit t('helpers.submit.hyrax_permission_template_access.create'), class: 'btn btn-info edit-collection-add-sharing-button ml-2', :disabled => true %> + + </div> <!-- /.form-inline --> + <% end %> + </div> + + <p class="form-text mt-2"><em><%= t('hyrax.admin.admin_sets.form.note') %></em></p> + </section> - <p class="help-block"><%= t('hyrax.admin.admin_sets.form.note') %></p> - </section> + <h2 class="h3"><%= t(".current_shared") %></h2> + <section class="section-collection-sharing"> - <section class="section-collection-sharing"> - <legend><%= t(".current_shared") %></legend> - <%= render 'form_share_table', access: 'managers', filter: :manage? %> - <%= render 'form_share_table', access: 'depositors', filter: :deposit? %> - <%= render 'form_share_table', access: 'viewers', filter: :view? %> - </section> - </div> + <%= render 'form_share_table', access: 'managers', filter: :manage? %> + <%= render 'form_share_table', access: 'depositors', filter: :deposit? %> + <%= render 'form_share_table', access: 'viewers', filter: :view? %> + </section> </div> </div> diff --git a/app/views/hyrax/dashboard/collections/_form_share_table.html.erb b/app/views/hyrax/dashboard/collections/_form_share_table.html.erb index 32b6f3dbc..e610153c7 100644 --- a/app/views/hyrax/dashboard/collections/_form_share_table.html.erb +++ b/app/views/hyrax/dashboard/collections/_form_share_table.html.erb @@ -1,36 +1,39 @@ -<%# OVERRIDE Hyrax v3.4.2 Filter out Role accesses as they should never be removed %> -<h3><%= t(".#{access}.title") %></h3> -<p><%= t(".#{access}.help") %></p> -<p><%= t(".#{access}.help_with_works", type_title: @collection.collection_type.title) if @collection.share_applies_to_new_works? && access != 'depositors' %></p> -<%# OVERRIDE: use custom filtering method to filter out access_grants for Collection Roles %> -<% if @form.filter_access_grants_by_access(filter).any? %> - <%# OVERRIDE: use custom access-specific class in order to differentiate between access tables %> - <table class='table table-striped share-status <%= "#{access}-table" %>'> - <thead> - <tr> - <th><%= t(".#{access}.agent_name") %></th> - <th><%= t(".#{access}.type") %></th> - <th><%= t(".#{access}.action") %></th> - </tr> - </thead> - <tbody> - <%# OVERRIDE: use custom filtering method to filter out access_grants for Collection Roles %> - <% @form.filter_access_grants_by_access(filter).each do |g| %> - <tr> - <td data-agent="<%= g.agent_id %>"><%= g.label %></td> - <td><%= g.agent_type.titleize %></td> - <td> - <%# OVERRIDE: only disable button if it is for the admin group's MANAGE access %> - <% if g.admin_group? && g.access == Hyrax::PermissionTemplateAccess::MANAGE %> - <%= link_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger disabled', disabled: true, title: t('hyrax.admin.admin_sets.form.permission_destroy_errors.admin_group') %> - <% else %> - <%= link_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger' %> - <% end %> - </td> - </tr> - <% end %> - </tbody> - </table> -<% else %> - <p><em><%= t(".#{access}.empty") %></em></p> -<% end %> +<%# OVERRIDE Hyrax v5.0.0rc2 Filter out Role accesses as they should never be removed %> +<div class="mb-4"> + + <h3 class="h4"><%= t(".#{access}.title") %></h3> + <p><%= t(".#{access}.help") %></p> + <p><%= t(".#{access}.help_with_works", type_title: @collection_type.title) if @collection_type.share_applies_to_new_works? && access != 'depositors' %></p> + <%# OVERRIDE: use custom filtering method to filter out access_grants for Collection Roles %> + <% if @form.filter_access_grants_by_access(filter).any? %> + <%# OVERRIDE: use custom access-specific class in order to differentiate between access tables %> + <table class='table table-striped share-status <%= "#{access}-table" %>'> + <thead> + <tr> + <th><%= t(".#{access}.agent_name") %></th> + <th><%= t(".#{access}.type") %></th> + <th><%= t(".#{access}.action") %></th> + </tr> + </thead> + <tbody> + <%# OVERRIDE: use custom filtering method to filter out access_grants for Collection Roles %> + <% @form.filter_access_grants_by_access(filter).each do |g| %> + <tr> + <td data-agent="<%= g.agent_id %>"><%= g.label %></td> + <td><%= g.agent_type.titleize %></td> + <td> + <%# OVERRIDE: only disable button if it is for the admin group's MANAGE access %> + <% if g.admin_group? && g.access == Hyrax::PermissionTemplateAccess::MANAGE %> + <%= link_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger disabled', disabled: true, title: t('hyrax.admin.admin_sets.form.permission_destroy_errors.admin_group') %> + <% else %> + <%= link_to t(".#{access}.remove"), hyrax.admin_permission_template_access_path(g), method: :delete, class: 'btn btn-sm btn-danger' %> + <% end %> + </td> + </tr> + <% end %> + </tbody> + </table> + <% else %> + <p><em><%= t(".#{access}.empty") %></em></p> + <% end %> +</div> diff --git a/app/views/hyrax/dashboard/collections/_list_collections.html.erb b/app/views/hyrax/dashboard/collections/_list_collections.html.erb index 2aa00e907..e09609066 100644 --- a/app/views/hyrax/dashboard/collections/_list_collections.html.erb +++ b/app/views/hyrax/dashboard/collections/_list_collections.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax 3.5.0 to add appropriate alt tag %> +<%# OVERRIDE Hyrax v5.0.0rc2 to add appropriate alt tag %> <% # used by All and Managed Collections tabs %> <% id = collection_presenter.id %> @@ -37,7 +37,7 @@ <%# Expand arrow %> <a href="#" class="small show-more" title="Click for more details"> - <i id="expand_<%= id %>" class="glyphicon glyphicon-chevron-right" aria-hidden="true"></i> + <i id="expand_<%= id %>" class="fa fa-chevron-right" aria-hidden="true"></i> <span class="sr-only"> <%= "#{t("hyrax.dashboard.my.sr.detail_label")} #{collection_presenter.title_or_label}" %></span> </a> </div> diff --git a/app/views/hyrax/dashboard/collections/_show_add_items_actions.html.erb b/app/views/hyrax/dashboard/collections/_show_add_items_actions.html.erb index b8d696ba8..eec369b21 100644 --- a/app/views/hyrax/dashboard/collections/_show_add_items_actions.html.erb +++ b/app/views/hyrax/dashboard/collections/_show_add_items_actions.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 Restrict who can deposit new works through collections %> +<%# OVERRIDE Hyrax v5.0.0rc2 Restrict who can deposit new works through collections %> <h2 class="sr-only"><%= t('hyrax.collection.actions.header') %></h2> <div class="text-right"> <%# OVERRIDE: add check for :manage_items_in_collection permission %> @@ -8,7 +8,7 @@ <%= link_to t('hyrax.collection.actions.add_new_work.label'), '#', title: t('hyrax.collection.actions.add_new_work.desc'), - data: { behavior: "select-work", target: "#worktypes-to-create", 'create-type' => 'single', add_works_to_collection: presenter.id }, + data: { behavior: "select-work", toggle: 'modal', target: "#worktypes-to-create", 'create-type' => 'single', add_works_to_collection: presenter.id }, class: 'btn btn-primary deposit-new-work-through-collection' %> <%# OVERRIDE: add #create_any_work_types? check %> <% elsif @presenter.create_any_work_types? # simple link to the first work type %> diff --git a/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb b/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb index 9536b69a8..2df61e46f 100644 --- a/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb +++ b/app/views/hyrax/dashboard/collections/_show_document_list_row.html.erb @@ -1,20 +1,22 @@ -<%# OVERRIDE Hyrax v3.4.2 Restrict who can remove works from collections %> +<%# OVERRIDE Hyrax v5.0.0rc2 Restrict who can remove works from collections %> <% id = document.id %> <tr id="document_<%= id %>"> <td>  <% if current_user and document.depositor != current_user.user_key %> - <i class="glyphicon glyphicon-share-alt" /> + <i class="fa fa-share" /> <% end %> </td> <td> <div class="media"> <%= link_to [main_app, document], "class" => "media-left", "aria-hidden" => "true" do %> - <%= render_thumbnail_tag document, { class: "hidden-xs file_listing_thumbnail", alt: document.title_or_label }, { suppress_link: true } %> + <%= document_presenter(document)&.thumbnail&.thumbnail_tag( + { class: "d-none d-md-block file_listing_thumbnail", alt: document.title_or_label }, { suppress_link: true } + ) %> <% end %> <div class="media-body"> <p class="media-heading"> <strong><%= link_to document.title_or_label, [main_app, document], id: "src_copy_link#{id}", class: "#{'document-title' if document.title_or_label == document.label}" %></strong> - <a href="#" class="small" title="Click for more details"><i id="expand_<%= id %>" class="glyphicon glyphicon-chevron-right"></i></a> + <a href="#" class="small" title="Click for more details"><i id="expand_<%= id %>" class="fa fa-chevron-right"></i></a> </p> <%= render_other_collection_links(document, @presenter.id) %> </div> @@ -26,21 +28,21 @@ <%= render_visibility_link(document) %> </td> <%# OVERRIDE: add check for :manage_items_in_collection permission %> - <% if current_user && can?(:edit, @collection) && can?(:manage_items_in_collection, @collection) %> + <% if current_user && can?(:edit, @collection) && can?(:manage_items_in_collection, @collection) %> <td class="text-center"> - <%= button_for_remove_from_collection @collection, document, label: "Remove", btn_class: "btn-danger btn-xs" %> + <%= button_for_remove_from_collection @collection, document, label: "Remove", btn_class: "btn-danger btn-sm" %> </td> <% end %> </tr> <tr id="detail_<%= id %>"> <!-- document detail"> --> <td colspan="6"> <dl class="expanded-details row"> - <dt class="col-xs-3 col-lg-2"><%= t('.creator') %></dt> - <dd class="col-xs-9 col-lg-4"><%= document.creator.to_a.to_sentence %></dd> - <dt class="col-xs-3 col-lg-2"><%= t('.depositor') %></dt> - <dd class="col-xs-9 col-lg-4"><%= link_to_profile document.depositor %></dd> - <dt class="col-xs-3 col-lg-2"><%= t('.edit_access') %></dt> - <dd class="col-xs-9 col-lg-10"> + <dt class="col-3 col-lg-2"><%= t('.creator') %></dt> + <dd class="col-9 col-lg-4"><%= document.creator.to_a.to_sentence %></dd> + <dt class="col-3 col-lg-2"><%= t('.depositor') %></dt> + <dd class="col-9 col-lg-4"><%= link_to_profile document.depositor %></dd> + <dt class="col-3 col-lg-2"><%= t('.edit_access') %></dt> + <dd class="col-9 col-lg-10"> <% if document.edit_groups.present? %> Groups: <%= document.edit_groups.join(', ') %> <br /> diff --git a/app/views/hyrax/dashboard/collections/_show_parent_collection_row.html.erb b/app/views/hyrax/dashboard/collections/_show_parent_collection_row.html.erb index 57712e092..8eea2e28f 100644 --- a/app/views/hyrax/dashboard/collections/_show_parent_collection_row.html.erb +++ b/app/views/hyrax/dashboard/collections/_show_parent_collection_row.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 Restrict who can remove parent collections from subcollections %> +<%# OVERRIDE Hyrax v5.0.0rc2 Restrict who can remove parent collections from subcollections %> <li data-id="<%= id %>" data-parent-id="<%= document.id %>" @@ -10,10 +10,10 @@ <% if can? :edit, id %> <%# OVERRIDE: add check for :manage_items_in_collection %> <% if can?(:edit, document.id) && can?(:manage_items_in_collection, document.id) %> - <button class="btn btn-xs btn-danger remove-from-collection-button"><%= t('hyrax.collections.show.buttons.remove_from_collection') %></button> + <button class="btn btn-sm btn-danger remove-from-collection-button"><%= t('hyrax.collections.show.buttons.remove_from_collection') %></button> <% else %> <%= link_to "#", - class: 'btn btn-xs btn-danger remove-parent-from-collection-deny-button', + class: 'btn btn-sm btn-danger remove-parent-from-collection-deny-button', title: t('hyrax.collections.show.buttons.remove_from_collection') do %> <%= t('hyrax.collections.show.buttons.remove_from_collection') %> <% end %> diff --git a/app/views/hyrax/dashboard/collections/_subcollection_list.html.erb b/app/views/hyrax/dashboard/collections/_subcollection_list.html.erb index a26bd9a82..da9a286a5 100644 --- a/app/views/hyrax/dashboard/collections/_subcollection_list.html.erb +++ b/app/views/hyrax/dashboard/collections/_subcollection_list.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 Restrict who can remove subcollections from collection %> +<%# OVERRIDE Hyrax v5.0.0rc2 Restrict who can remove subcollections from collection %> <% if @subcollection_docs.nil? || @subcollection_docs.empty? %> <div class="alert alert-warning" role="alert"><%= t('hyrax.collections.show.no_visible_subcollections') %></div> <% else %> @@ -15,7 +15,7 @@ </div> <%# OVERRIDE: add :manage_items_in_collection check %> <% if can?(:edit, document.id) && can?(:manage_items_in_collection, id) %> - <button class="btn btn-xs btn-danger remove-subcollection-button"><%= t('hyrax.collections.show.buttons.remove_this_sub_collection') %></button> + <button class="btn btn-sm btn-danger remove-subcollection-button"><%= t('hyrax.collections.show.buttons.remove_this_sub_collection') %></button> <% end %> </div> </li> @@ -25,5 +25,5 @@ <% end %> <% if can? :edit, id %> - <%= render 'modal_remove_sub_collection' %> +<%= render 'modal_remove_sub_collection' %> <% end %> diff --git a/app/views/hyrax/dashboard/sidebar/_activity.html.erb b/app/views/hyrax/dashboard/sidebar/_activity.html.erb index a75c4eb07..770f0b449 100644 --- a/app/views/hyrax/dashboard/sidebar/_activity.html.erb +++ b/app/views/hyrax/dashboard/sidebar/_activity.html.erb @@ -1,85 +1,97 @@ - <li class="h5"><%= t('hyrax.admin.sidebar.activity') %></li> +<%# OVERRIDE Hyrax v5.0.0rc2 to add title attribute to nav links %> +<li class="h5 nav-item"><%= t('hyrax.admin.sidebar.activity') %></li> - <li> - <%= menu.collapsable_section t('hyrax.admin.sidebar.repository_activity'), - icon_class: "fa fa-line-chart", - id: 'collapseRepositoryActivity', - open: menu.repository_activity_section?, - title: t('hyrax.admin.sidebar.repository_activity') do %> - <%= menu.nav_link(hyrax.dashboard_path, - title: t('hyrax.admin.sidebar.activity_summary')) do %> - <span class="fa fa-dashboard"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.activity_summary') %></span> - <% end %> - <% if menu.show_admin_menu_items? %> - <%= menu.nav_link(main_app.status_path, - title: t('hyrax.admin.sidebar.system_status')) do %> - <span class="fa fa-flag"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.system_status') %></span> - <% end %> +<li class="nav-item"> + <%= menu.collapsable_section t('hyrax.admin.sidebar.repository_activity'), + icon_class: "fa fa-line-chart", + id: 'collapseRepositoryActivity', + open: menu.repository_activity_section?, + title: t('hyrax.admin.sidebar.repository_activity') do %> + <%= menu.nav_link(hyrax.dashboard_path, + class: "nav-link", + title: t('hyrax.admin.sidebar.activity_summary')) do %> + <span class="fa fa-dashboard"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.activity_summary') %></span> + <% end %> + <% if menu.show_admin_menu_items? %> + <%= menu.nav_link(main_app.status_path, + class: "nav-link", + title: t('hyrax.admin.sidebar.system_status')) do %> + <span class="fa fa-flag"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.system_status') %></span> <% end %> <% end %> - </li> + <% end %> +</li> - <li> - <%= menu.collapsable_section t('hyrax.admin.sidebar.user_activity'), - icon_class: "fa fa-line-chart", - id: 'collapseUserActivity', - open: menu.user_activity_section?, - title: t('hyrax.admin.sidebar.user_activity') do %> - <%= menu.nav_link(hyrax.dashboard_profile_path(current_user), - also_active_for: hyrax.edit_dashboard_profile_path(current_user), - title: t('hyrax.admin.sidebar.profile')) do %> - <span class="fa fa-id-card" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.profile') %></span> - <% end %> +<li class="nav-item"> + <%= menu.collapsable_section t('hyrax.admin.sidebar.user_activity'), + icon_class: "fa fa-line-chart", + id: 'collapseUserActivity', + open: menu.user_activity_section?, + title: t('hyrax.admin.sidebar.user_activity') do %> + <%= menu.nav_link(hyrax.dashboard_profile_path(current_user), + class: "nav-link", + also_active_for: hyrax.edit_dashboard_profile_path(current_user), + title: t('hyrax.admin.sidebar.profile')) do %> + <span class="fa fa-id-card" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.profile') %></span> + <% end %> - <%= menu.nav_link(hyrax.notifications_path, - title: t('hyrax.admin.sidebar.notifications')) do %> - <span class="fa fa-bell" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.notifications') %></span> - <% end %> + <%= menu.nav_link(hyrax.notifications_path, + class: "nav-link", + title: t('hyrax.admin.sidebar.notifications')) do %> + <span class="fa fa-bell" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.notifications') %></span> + <% end %> - <%= menu.nav_link(hyrax.transfers_path, - title: t('hyrax.admin.sidebar.transfers')) do %> - <span class="fa fa-arrows-h" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.transfers') %></span> - <% end %> + <%= menu.nav_link(hyrax.transfers_path, + class: "nav-link", + title: t('hyrax.admin.sidebar.transfers')) do %> + <span class="fa fa-arrows-h" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.transfers') %></span> + <% end %> - <% if Flipflop.proxy_deposit? %> - <%= menu.nav_link(hyrax.depositors_path, - title: t('hyrax.dashboard.manage_proxies')) do %> - <span class="fa fa-users" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.dashboard.manage_proxies') %></span> - <% end %> + <% if Flipflop.proxy_deposit? %> + <%= menu.nav_link(hyrax.depositors_path, + class: "nav-link", + title: t('hyrax.dashboard.manage_proxies')) do %> + <span class="fa fa-users" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.dashboard.manage_proxies') %></span> <% end %> <% end %> - </li> + <% end %> +</li> - <% if can? :read, :admin_dashboard %> +<% if can? :read, :admin_dashboard %> + <li class="nav-item"> <%= menu.nav_link(hyrax.admin_stats_path, + class: "nav-link", title: t('hyrax.admin.sidebar.statistics')) do %> <span class="fa fa-bar-chart" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.statistics') %></span> <% end %> - <% end %> - - <% if current_ability.can_create_any_work? && Hyrax.config.analytics? %> - <li> - <%= menu.collapsable_section t('hyrax.admin.sidebar.analytics'), - icon_class: "fa fa-pie-chart", - id: 'collapseAnalytics', - open: menu.analytics_reporting_section?, - title: t('hyrax.admin.sidebar.analytics') do %> - <% if can? :read, :admin_dashboard %> - <%= menu.nav_link(hyrax.admin_analytics_collection_reports_path, - onclick: "dontChangeAccordion(event);", - title: t('hyrax.admin.sidebar.collections_report')) do %> - <span class="fa fa-folder-open" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.collections_report') %></span> - <% end %> - <% end %> + </li> +<% end %> - <%= menu.nav_link(hyrax.admin_analytics_work_reports_path, +<% if current_ability.can_create_any_work? && Hyrax.config.analytics? %> + <li class="nav-item"> + <%= menu.collapsable_section t('hyrax.admin.sidebar.analytics'), + icon_class: "fa fa-pie-chart", + id: 'collapseAnalytics', + open: menu.analytics_reporting_section?, + title: t('hyrax.admin.sidebar.analytics') do %> + <% if can? :read, :admin_dashboard %> + <%= menu.nav_link(hyrax.admin_analytics_collection_reports_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", - title: t('hyrax.admin.sidebar.works_report')) do %> - <span class="fa fa-file" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.works_report') %></span> + title: t('hyrax.admin.sidebar.collections_report')) do %> + <span class="fa fa-folder-open" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.collections_report') %></span> <% end %> + <% end %> + <%= menu.nav_link(hyrax.admin_analytics_work_reports_path, + class: "nav-link", + onclick: "dontChangeAccordion(event);", + title: t('hyrax.admin.sidebar.works_report')) do %> + <span class="fa fa-file" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.works_report') %></span> <% end %> - </li> - <% end %> - <%= render 'hyrax/dashboard/sidebar/menu_partials', menu: menu, section: :activity %> + <% end %> + </li> +<% end %> + +<%= render 'hyrax/dashboard/sidebar/menu_partials', menu: menu, section: :activity %> diff --git a/app/views/hyrax/dashboard/sidebar/_configuration.html.erb b/app/views/hyrax/dashboard/sidebar/_configuration.html.erb index ec2bce02c..85184aab0 100644 --- a/app/views/hyrax/dashboard/sidebar/_configuration.html.erb +++ b/app/views/hyrax/dashboard/sidebar/_configuration.html.erb @@ -1,63 +1,76 @@ +<%# OVERRIDE Hyrax v5.0.0rc2 add accoun settings and title attributes %> + <% if menu.show_configuration? %> - <li class="h5"><%= t('hyrax.admin.sidebar.configuration') %></li> + <li class="h5 nav-item"><%= t('hyrax.admin.sidebar.configuration') %></li> <% if can? :manage, Site %> - <li> + <li class="nav-item"> <%= menu.collapsable_section t('hyrax.admin.sidebar.settings'), icon_class: "fa fa-cog", id: 'collapseSettings', open: menu.settings_section?, title: t('hyrax.admin.sidebar.settings') do %> <%= menu.nav_link(main_app.edit_admin_account_path, + class: "nav-link", title: t('hyrax.admin.sidebar.account')) do %> <span class="fa fa-gear"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.account') %></span> <% end %> - <%= menu.nav_link(main_app.identity_providers_path) do %> - <span class="fa fa-key"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.identity_providers') %></span> + <%= menu.nav_link(main_app.identity_providers_path, class: "nav-link") do %> + <span class="fa fa-key"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.identity_provider') %></span> <% end %> <%= menu.nav_link(main_app.edit_site_labels_path, + class: "nav-link", title: t('hyrax.admin.sidebar.labels')) do %> <span class="fa fa-institution"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.labels') %></span> <% end %> <% if can?(:update, :appearance) %> <%= menu.nav_link(hyrax.admin_appearance_path, + class: "nav-link", title: t('hyrax.admin.sidebar.appearance')) do %> <span class="fa fa-paint-brush" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.appearance') %></span> <% end %> <% end %> <% if can?(:manage, :collection_types) %> <%= menu.nav_link(hyrax.admin_collection_types_path, + class: "nav-link", title: t('hyrax.admin.sidebar.collection_types')) do %> <span class="fa fa-folder-open" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.collection_types') %></span> <% end %> <% end %> <% if can?(:manage, Hyrax::Feature) %> <%= menu.nav_link(hyrax.edit_pages_path, + class: "nav-link", title: t('hyrax.admin.sidebar.pages')) do %> <span class="fa fa-file-text-o" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.pages') %></span> <% end %> <%= menu.nav_link(hyrax.edit_content_blocks_path, + class: "nav-link", title: t('hyrax.admin.sidebar.content_blocks')) do %> <span class="fa fa-square-o" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.content_blocks') %></span> <% end %> <%= menu.nav_link(hyrax.admin_features_path, + class: "nav-link", title: t('hyrax.admin.sidebar.technical')) do %> <span class="fa fa-wrench" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.technical') %></span> <% end %> <%= menu.nav_link('/admin/work_types/edit', + class: "nav-link", title: t('hyku.admin.work_types')) do %> <span class="fa fa-address-book"></span> <span class="sidebar-action-text"><%= t('hyku.admin.work_types') %></span> <% end %> <% end %> + <% end %> </li> <% end %> + <% if can?(:manage, Sipity::WorkflowResponsibility) %> <%= menu.nav_link(hyrax.admin_workflow_roles_path, + class: "nav-link", title: t('hyrax.admin.sidebar.workflow_roles')) do %> <span class="fa fa-users" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.workflow_roles') %></span> <% end %> - <% end # end of configuration block %> - <%= render 'hyrax/dashboard/sidebar/menu_partials', menu: menu, section: :configuration %> - <% end %> + <% end # end of configuration block %> + + <%= render 'hyrax/dashboard/sidebar/menu_partials', menu: menu, section: :configuration %> <% end %> diff --git a/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb b/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb index 556de0170..fde8c553d 100644 --- a/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb +++ b/app/views/hyrax/dashboard/sidebar/_repository_content.html.erb @@ -1,7 +1,8 @@ <%# override from bulkrax to make bulkrax a feature flipper %> -<li class="h5"><%= t('hyrax.admin.sidebar.repository_objects') %></li> +<li class="h5 nav-item"><%= t('hyrax.admin.sidebar.repository_objects') %></li> <%= menu.nav_link(hyrax.my_collections_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", also_active_for: hyrax.dashboard_collections_path, title: t('hyrax.admin.sidebar.collections')) do %> @@ -9,6 +10,7 @@ <% end %> <%= menu.nav_link(hyrax.my_works_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", also_active_for: hyrax.dashboard_works_path, title: t('hyrax.admin.sidebar.works')) do %> @@ -17,11 +19,13 @@ <% if ENV.fetch('HYKU_BULKRAX_ENABLED', 'true') == 'true' %> <%= menu.nav_link(bulkrax.importers_path, + class: "nav-link", title: t('bulkrax.admin.sidebar.importers')) do %> <span class="fa fa-cloud-upload" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('bulkrax.admin.sidebar.importers') %></span> <% end %> <%= menu.nav_link(bulkrax.exporters_path, + class: "nav-link", title: t('bulkrax.admin.sidebar.exporters')) do %> <span class="fa fa-cloud-download" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('bulkrax.admin.sidebar.exporters') %></span> <% end %> diff --git a/app/views/hyrax/dashboard/sidebar/_tasks.html.erb b/app/views/hyrax/dashboard/sidebar/_tasks.html.erb index 30a932867..d10a64591 100644 --- a/app/views/hyrax/dashboard/sidebar/_tasks.html.erb +++ b/app/views/hyrax/dashboard/sidebar/_tasks.html.erb @@ -1,9 +1,12 @@ +<%# OVERRIDE Hyrax v5.0.0rc2 to add Groups and title attributes %> + <% if menu.show_task? %> - <li class="h5"><%= t('hyrax.admin.sidebar.tasks') %></li> + <li class="h5 nav-item"><%= t('hyrax.admin.sidebar.tasks') %></li> <% end %> <% if can? :review, :submissions %> <%= menu.nav_link(hyrax.admin_workflows_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", title: t('hyrax.admin.sidebar.workflow_review')) do %> <span class="fa fa-flag" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.workflow_review') %></span> @@ -12,6 +15,7 @@ <% if can? :read, User %> <%= menu.nav_link(hyrax.admin_users_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", title: t('hyrax.admin.sidebar.users')) do %> <span class="fa fa-user" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.users') %></span> @@ -20,6 +24,7 @@ <% if can? :read, Hyrax::Group %> <%= menu.nav_link(main_app.admin_groups_path, + class: "nav-link", title: t('hyrax.admin.sidebar.manage_groups')) do %> <span class="fa fa-users"></span> <span class="sidebar-action-text"><%= t('hyrax.admin.sidebar.manage_groups') %></span> <% end %> @@ -27,12 +32,14 @@ <% if can? :read, :admin_dashboard %> <%= menu.nav_link(hyrax.embargoes_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", title: t('hyrax.embargoes.index.manage_embargoes')) do %> <span class="fa fa-flag" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.embargoes.index.manage_embargoes') %></span> <% end %> <%= menu.nav_link(hyrax.leases_path, + class: "nav-link", onclick: "dontChangeAccordion(event);", title: t('hyrax.leases.index.manage_leases')) do %> <span class="fa fa-flag" aria-hidden="true"></span> <span class="sidebar-action-text"><%= t('hyrax.leases.index.manage_leases') %></span> diff --git a/app/views/hyrax/dashboard/works/_list_works.html.erb b/app/views/hyrax/dashboard/works/_list_works.html.erb index 4c0405c59..275a3031a 100644 --- a/app/views/hyrax/dashboard/works/_list_works.html.erb +++ b/app/views/hyrax/dashboard/works/_list_works.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax 3.5.0 to add appropriate alt tag %> +<%# OVERRIDE Hyrax v5.0.0rc2 to add appropriate alt tag %> <tr id="document_<%= document.id %>"> <td> @@ -8,7 +8,12 @@ <td> <div class='media'> <%= link_to [main_app, document], class: 'media-left' do %> - <%= render_thumbnail_tag document, { class: 'hidden-xs file_listing_thumbnail', alt: block_for(name: 'default_work_image_text') || "#{document.title_or_label} #{t('hyrax.homepage.admin_sets.thumbnail')}" }, { suppress_link: true } %> + <%# OVERRIDE begin %> + <%= document_presenter(document)&.thumbnail&.thumbnail_tag( + { class: 'd-none d-md-block file_listing_thumbnail', alt: block_for(name: 'default_work_image_text') || "#{document.title_or_label} #{t('hyrax.homepage.admin_sets.thumbnail')}" }, + { suppress_link: true } + ) %> + <%# OVERRIDE end %> <% end %> <div class='media-body'> diff --git a/app/views/hyrax/homepage/_explore_collections.html.erb b/app/views/hyrax/homepage/_explore_collections.html.erb index 3a93a347c..77e343781 100644 --- a/app/views/hyrax/homepage/_explore_collections.html.erb +++ b/app/views/hyrax/homepage/_explore_collections.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE from Hyrax 2.9.0 to add featured collection functionality %> +<%# OVERRIDE from Hyrax v5.0.0rc2 to add featured collection functionality %> <% featured_collection = f.object.presenter %> <tr> @@ -7,7 +7,7 @@ <div> <%= link_to [hyrax, featured_collection] do %> <%= render_thumbnail_tag(featured_collection, - { class: 'img-responsive hidden-xs file_listing_thumbnail', alt: "#{featured_collection.title_or_label} #{ t('hyrax.homepage.admin_sets.thumbnail')}" }, + { class: 'img-fluid d-none d-sm-block file_listing_thumbnail', alt: "#{featured_collection.title_or_label} #{ t('hyrax.homepage.admin_sets.thumbnail')}" }, {suppress_link: true} ) %> <% end %> @@ -17,7 +17,6 @@ <%= featured_collection.title.first %> <% end %> </div> - </div> </div> </td> </tr> diff --git a/app/views/hyrax/homepage/_featured_collection_fields.html.erb b/app/views/hyrax/homepage/_featured_collection_fields.html.erb index 16b89026b..70b1cfc49 100644 --- a/app/views/hyrax/homepage/_featured_collection_fields.html.erb +++ b/app/views/hyrax/homepage/_featured_collection_fields.html.erb @@ -2,16 +2,16 @@ <div class="sr-only"> <%= t('hyrax.homepage.featured_collections.document.title_label') %> </div> - <div class= 'homepage-work-thumbnail'> + <div class='homepage-work-thumbnail'> + <%= link_to [hyrax, featured] do %> + <%= render_thumbnail_tag(featured.solr_document, {suppress_link: true}) %> + <% end %> + </div> + <div> + <h5> <%= link_to [hyrax, featured] do %> - <%= render_thumbnail_tag(featured.solr_document, {suppress_link: true}) %> - <% end %> - </div> - <div> - <h5> - <%= link_to [hyrax, featured] do %> - <%= featured.title.first %> - <% end %> - </h5> - </div> -</div> \ No newline at end of file + <%= featured.title.first %> + <% end %> + </h5> + </div> +</div> diff --git a/app/views/hyrax/homepage/_featured_collection_section.html.erb b/app/views/hyrax/homepage/_featured_collection_section.html.erb index 728832826..509ba7e87 100644 --- a/app/views/hyrax/homepage/_featured_collection_section.html.erb +++ b/app/views/hyrax/homepage/_featured_collection_section.html.erb @@ -1,18 +1,18 @@ - <% if @featured_collection_list.empty? %> - <p id='no-collections'><%= t('hyrax.homepage.featured_collections.no_collections') %></p> - <% elsif can? :update, FeaturedCollection %> +<% if @featured_collection_list.empty? %> + <p id='no-collections'><%= t('hyrax.homepage.featured_collections.no_collections') %></p> +<% elsif can? :update, FeaturedCollection %> <%= form_for [main_app, @featured_collection_list] do |f| %> - <div class="panel-group dd" id="ff"> + <div class="card-group dd" id="ff"> <ol id="featured_works"> <%= f.fields_for :featured_collections do |featured| %> <%= render 'sortable_featured_collections', f: featured %> <% end %> </ol> </div> - <%= f.submit("Save order", class: 'btn btn-default') %> + <%= f.submit("Save order", class: 'btn btn-secondary') %> <% end %> - <% else %> - <table class="table table-striped collection-highlights"> +<% else %> + <table class="table table-striped collection-highlights"> <tbody> <%= form_for [main_app, @featured_collection_list] do |f| %> <%= f.fields_for :featured_collections do |featured| %> @@ -21,12 +21,11 @@ <% end %> </tbody> </table> - <% end %> +<% end %> <ul class="list-inline collection-highlights-list"> <li> <%= link_to t('hyrax.homepage.admin_sets.link'), - main_app.search_catalog_path(f: { human_readable_type_sim: ["Collection"]}), - class: 'btn btn-default' %> + main_app.search_catalog_path(f: { human_readable_type_sim: ["Collection"]}), + class: 'btn btn-secondary' %> </li> </ul> - diff --git a/app/views/hyrax/homepage/_featured_fields.html.erb b/app/views/hyrax/homepage/_featured_fields.html.erb index 4c5e2e630..3a16f1dca 100644 --- a/app/views/hyrax/homepage/_featured_fields.html.erb +++ b/app/views/hyrax/homepage/_featured_fields.html.erb @@ -1,10 +1,12 @@ -<%# OVERRIDE Hyrax 2.9.1 to remove the hardcorded image width %> +<%# OVERRIDE Hyrax v5.0.0rc2 to remove the hardcorded image width %> <div> <div class="featured-item-title"> <span class="sr-only"><%= t('hyrax.homepage.featured_works.document.title_label') %></span> <h3> <%= link_to [main_app, featured] do %> + <%# OVERRIDE begin %> <%= render_thumbnail_tag(featured, {alt: "#{featured.title.first.to_s} #{ t('hyrax.homepage.admin_sets.thumbnail')}" }, {suppress_link: true}) + featured.title.first %> + <%# OVERRIDE end %> <% end %> </h3> </div> diff --git a/app/views/hyrax/homepage/_home_content.html.erb b/app/views/hyrax/homepage/_home_content.html.erb index ec03f25d9..a58739be2 100644 --- a/app/views/hyrax/homepage/_home_content.html.erb +++ b/app/views/hyrax/homepage/_home_content.html.erb @@ -1,49 +1,64 @@ -<%# Override from hyrax 2.5.1 to add feature flags to show/hide: +<%# Override from Hyrax v5.0.0rc2 to add feature flags to show/hide: featured researcher featured works recently_uploaded also, to render featured collections %> -<div class="<%= @presenter.display_featured_works? || @presenter.display_recently_uploaded? ? 'home-tabs-left col-sm-6' : ''%>"> +<div class="<%= @presenter.display_featured_works? || @presenter.display_recently_uploaded? ? 'home-tabs-left col-md-6' : '' %>"> <ul id="homeTabs" class="nav nav-tabs" role="list"> <%# add check for featured works %> <% if @presenter.display_featured_works? %> - <li class="active"><a href="#featured_container" data-toggle="tab" id="featureTab"><%= t('hyrax.homepage.featured_works.tab_label') %></a></li> + <li class="nav-item"> + <a class="nav-link active" href="#featured_container" data-toggle="tab" id="featureTab"> + <%= t('hyrax.homepage.featured_works.tab_label') %> + </a> + </li> <% end %> <%# add check for recently uploaded %> <% if @presenter.display_recently_uploaded? %> - <li class="<%= @presenter.display_featured_works? ? '' : 'active' %>"><a href="#recently_uploaded" data-toggle="tab" id="recentTab"><%= t('hyrax.homepage.recently_uploaded.tab_label') %></a></li> + <li class="nav-item <%= @presenter.display_featured_works? ? '' : 'active' %>"> + <a class="nav-link" href="#recently_uploaded" data-toggle="tab" id="recentTab"> + <%= t('hyrax.homepage.recently_uploaded.tab_label') %> + </a> + </li> <% end %> </ul> <div class="tab-content"> <%# add check for featured works %> <% if @presenter.display_featured_works? %> - <div class="tab-pane fade in active" id="featured_container" role="tabpanel" aria-labelledby="featureTab"> + <div class="tab-pane show active" id="featured_container" role="tabpanel" aria-labelledby="featureTab"> <%= render 'featured_works' %> </div> <% end %> <%# add check for recently_uploaded %> <% if @presenter.display_recently_uploaded? %> - <div class="<%= @presenter.display_featured_works? ? 'tab-pane fade' : 'tab-pane active in' %>" id="recently_uploaded" role="tabpanel" aria-labelledby="recentTab"> + <div class="tab-pane <%= @presenter.display_featured_works? ? '' : 'show active' %>" id="recently_uploaded" role="tabpanel" aria-labelledby="recentTab"> <%= render 'recently_uploaded', recent_documents: @recent_documents %> </div> - <% end %> + <% end %> </div> -</div><!-- /.col-xs-6 --> +</div><!-- /.col-md-6 --> -<div class="home-tabs-right col-sm-6"> +<div class="home-tabs-right col-md-6"> <ul class="nav nav-tabs" role="list"> - <li class="active"><a aria-expanded="true" href="#tab-col2-first" data-toggle="tab"><%= t('hyrax.homepage.admin_sets.title') %></a></li> - <%# add check for featured researcher %> + <li class="nav-item active"> + <a class="nav-link" aria-expanded="true" href="#tab-col2-first" data-toggle="tab"> + <%= t('hyrax.homepage.admin_sets.title') %> + </a> + </li> <% if @presenter.display_featured_researcher? %> - <li class=""><a aria-expanded="false" href="#tab-col2-second" data-toggle="tab"><%= t('hyrax.homepage.featured_researcher.tab_label') %></a></li> + <li class="nav-item"> + <a class="nav-link" aria-expanded="false" href="#tab-col2-second" data-toggle="tab"> + <%= t('hyrax.homepage.featured_researcher.tab_label') %> + </a> + </li> <% end %> </ul> <div class="tab-content"> - <div class="tab-pane active" id="tab-col2-first"> + <div class="tab-pane show active" id="tab-col2-first"> <h2 class="sr-only"><%= t('hyrax.homepage.admin_sets.title') %></h2> <%= render 'featured_collection_section' %> </div> diff --git a/app/views/hyrax/homepage/_home_text.html.erb b/app/views/hyrax/homepage/_home_text.html.erb index 596f12d9a..558fd86ea 100644 --- a/app/views/hyrax/homepage/_home_text.html.erb +++ b/app/views/hyrax/homepage/_home_text.html.erb @@ -1,7 +1,9 @@ -# frozen_string_literal: true - <% if display_content_block? @home_text %> - <div class="home_page_text"> - <%= displayable_content_block @home_text, class: 'col-sm-3 home_page_text' %> + <div class="row"> + <div class="col-sm-3"> + <div class="home_page_text"> + <%= displayable_content_block @home_text %> + </div> + </div> </div> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/hyrax/homepage/_sortable_featured_collections.html.erb b/app/views/hyrax/homepage/_sortable_featured_collections.html.erb index 620f7b8e7..95f99cf43 100644 --- a/app/views/hyrax/homepage/_sortable_featured_collections.html.erb +++ b/app/views/hyrax/homepage/_sortable_featured_collections.html.erb @@ -3,17 +3,17 @@ <div class="dd-handle dd3-handle"> <%= t 'hyrax.homepage.featured_works.drag' %> </div> - <div class="dd3-content panel panel-default"> + <div class="dd3-content card"> <%= f.hidden_field :id %> <%= f.hidden_field :order, data: { property: "order" } %> - <div class="main row"> - <div class="col-sm-12"> + <div class="card-body row"> + <div class="col-md-12"> <% if can? :destroy, FeaturedCollection %> - <h3 class="pull-right"> + <h3 class="float-right"> <%= link_to main_app.featured_collection_path(presenter, format: :json), title: "Remove collection from feature section", data: {behavior: 'unfeature'} do %> - <i class='glyphicon glyphicon-remove'></i> + <i class='fas fa-times'></i> <% end %> <p class="sr-only"><%= t 'helpers.action.remove' %></p> </h3> diff --git a/app/views/hyrax/my/_collection_action_menu.html.erb b/app/views/hyrax/my/_collection_action_menu.html.erb index f5f92ca9a..98cc23db7 100644 --- a/app/views/hyrax/my/_collection_action_menu.html.erb +++ b/app/views/hyrax/my/_collection_action_menu.html.erb @@ -1,15 +1,14 @@ -<%# OVERRIDE Hyrax v3.4.2 Adjust collection deletion permissions %> +<%# OVERRIDE Hyrax v5.0.0rc2 Adjust collection deletion permissions %> <% id = collection_presenter.id %> <% ul_id = 'collection-action-dropdown-ul-' + id %> <div class="btn-group"> <button class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" type="button" id="dropdownMenu_<%= id %>" aria-haspopup="true" aria-expanded="false" aria-controls="<%= ul_id %>"> <span class="sr-only"><%= t("hyrax.dashboard.my.sr.press_to") %> </span> - <%= t("hyrax.dashboard.my.action.select") %> <span class="caret" aria-hidden="true"></span> + <%= t("hyrax.dashboard.my.action.select") %> </button> - <ul role="menu" id="<%= ul_id %>" class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu_<%= id %>"> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= link_to hyrax.dashboard_collection_path(id), class: 'itemicon itemedit', title: t("hyrax.dashboard.my.action.view_collection") do %> @@ -17,7 +16,7 @@ <% end %> </li> <% if can? :edit, collection_presenter.solr_document %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= link_to hyrax.edit_dashboard_collection_path(id), class: 'itemicon itemedit', title: t("hyrax.dashboard.my.action.edit_collection") do %> @@ -25,7 +24,7 @@ <% end %> </li> <% else %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= link_to "#", class: 'itemicon itemedit edit-collection-deny-button', title: t("hyrax.dashboard.my.action.edit_collection") do %> @@ -33,7 +32,7 @@ <% end %> </li> <% end %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%# OVERRIDE: change hasaccess to check if a user can destroy the solr_doc, not just if they can edit it %> <%= link_to "#", class: 'itemicon itemtrash delete-collection-button', @@ -47,7 +46,7 @@ <% if Hyrax::CollectionType.any_nestable? %> <% # The user should have deposit access to the parent we are adding, and read access to the child (the collection we are linking here). %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= link_to "#", class: 'itemicon add-to-collection', title: t("hyrax.dashboard.my.action.add_to_collection"), diff --git a/app/views/hyrax/my/_work_action_menu.html.erb b/app/views/hyrax/my/_work_action_menu.html.erb index 70e94b17f..61a02efc1 100644 --- a/app/views/hyrax/my/_work_action_menu.html.erb +++ b/app/views/hyrax/my/_work_action_menu.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax v3.4.2 Adjust #can? permission checks %> +<%# OVERRIDE Hyrax v5.0.0rc2 Adjust #can? permission checks %> <% ul_id = 'admin-set-action-dropdown-ul-' + document.id %> <div class="btn-group"> @@ -6,43 +6,43 @@ <button class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" type="button" id="dropdownMenu_<%= document.id %>" aria-haspopup="true" aria-expanded="false" aria-controls="<%= ul_id %>"> <span class="sr-only"><%= t("hyrax.dashboard.my.sr.press_to") %> </span> <%= t("hyrax.dashboard.my.action.select") %> - <span class="caret" aria-hidden="true"></span> </button> <ul role="menu" id="<%= ul_id %>" class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu_<%= document.id %>"> <% if can? :edit, document.id %> - <li role="menuitem" tabindex="-1"> - <%= link_to [main_app, :edit, document] do %> - <i class="glyphicon glyphicon-pencil" aria-hidden="true"></i> + <li class="dropdown-item" role="menuitem" tabindex="-1"> + <%= link_to [main_app, :edit, document], + id: 'action-edit-work' do %> + <i class="fa fa-pencil" aria-hidden="true"></i> <span> <%= t("hyrax.dashboard.my.action.edit_work") %> </span> <% end %> </li> <% end %> - <%# OVERRIDE: add separate #can? check for :delete instead of checking for :edit %> <% if can? :delete, document %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= link_to [main_app, document], method: :delete, + id: 'action-delete-work', data: { confirm: t("hyrax.dashboard.my.action.work_confirmation", application_name: application_name) } do %> - <i class="glyphicon glyphicon-trash" aria-hidden="true"></i> + <i class="fa fa-trash" aria-hidden="true"></i> <span> <%= t("hyrax.dashboard.my.action.delete_work") %> </span> <% end %> </li> <% end %> - <li role="menuitem" tabindex="-1"> + <li class="dropdown-item" role="menuitem" tabindex="-1"> <%= display_trophy_link(current_user, document.id) do |text| %> - <i class="glyphicon glyphicon-star" aria-hidden="true"></i> <%= text %> + <i class="fa fa-star" aria-hidden="true"></i> <%= text %> <% end %> </li> <% if can? :transfer, document.id %> - <li role="menuitem" tabindex="-1"> - <%= link_to(hyrax.new_work_transfer_path(document.id), class: 'itemicon itemtransfer', title: t("hyrax.dashboard.my.action.transfer")) do %> - <i class="glyphicon glyphicon-transfer" aria-hidden="true"></i> + <li class="dropdown-item" role="menuitem" tabindex="-1"> + <%= link_to(hyrax.new_work_transfer_path(document.id), id: 'action-transfer-work', class: 'itemicon itemtransfer', title: t("hyrax.dashboard.my.action.transfer")) do %> + <i class="fa fa-exchange" aria-hidden="true"></i> <span> <%= t("hyrax.dashboard.my.action.transfer") %> </span> <% end %> </li> diff --git a/app/views/hyrax/my/collections/_list_collections.html.erb b/app/views/hyrax/my/collections/_list_collections.html.erb index 7450a51e3..31efaec0f 100644 --- a/app/views/hyrax/my/collections/_list_collections.html.erb +++ b/app/views/hyrax/my/collections/_list_collections.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax 3.5.0 to add appropriate alt tag %> +<%# OVERRIDE Hyrax v5.0.0rc2 to add appropriate alt tag %> <% # used by Your Collections tab %> <% id = collection_presenter.id %> @@ -39,7 +39,7 @@ <%# Expand arrow %> <a href="#" class="small show-more" title="Click for more details"> - <i id="expand_<%= id %>" class="glyphicon glyphicon-chevron-right" aria-hidden="true"></i> + <i id="expand_<%= id %>" class="fa fa-chevron-right" aria-hidden="true"></i> <span class="sr-only"> <%= "#{t("hyrax.dashboard.my.sr.detail_label")} #{collection_presenter.title_or_label}" %></span> </a> </div> diff --git a/app/views/hyrax/my/works/_list_works.html.erb b/app/views/hyrax/my/works/_list_works.html.erb index 7b3424bad..d2a422778 100644 --- a/app/views/hyrax/my/works/_list_works.html.erb +++ b/app/views/hyrax/my/works/_list_works.html.erb @@ -1,4 +1,4 @@ -<%# OVERRIDE Hyrax 3.5.0 to add appropriate alt tag %> +<%# OVERRIDE Hyrax v5.0.0rc2 to add appropriate alt tag %> <tr id="document_<%= document.id %>"> @@ -9,14 +9,14 @@ <td> <div class='media'> + <%# OVERRIDE begin %> <%= link_to [main_app, document], class: 'media-left' do %> <%= render_thumbnail_tag document, { class: 'hidden-xs file_listing_thumbnail', alt: block_for(name: 'default_work_image_text') || "#{document.title_or_label} #{t('hyrax.homepage.admin_sets.thumbnail')}" }, { suppress_link: true } %> <% end %> + <%# OVERRIDE end %> <div class='media-body'> - <div class='media-heading'> - - <%= link_to [main_app, document], id: "src_copy_link#{document.id}", class: 'document-title' do %> + <%= link_to [main_app, document], id: "src_copy_link#{document.id}", class: 'document-title' do %> <span class="sr-only"> <%= t("hyrax.dashboard.my.sr.show_label") %> </span> @@ -25,8 +25,6 @@ <br /> <%= render_collection_links(document) %> - - </div> </div> </div> </td> diff --git a/app/views/hyrax/uploads/_js_templates_branding.html.erb b/app/views/hyrax/uploads/_js_templates_branding.html.erb index 7acaa6611..be00d2b19 100644 --- a/app/views/hyrax/uploads/_js_templates_branding.html.erb +++ b/app/views/hyrax/uploads/_js_templates_branding.html.erb @@ -1,8 +1,8 @@ - <!-- OVERRIDE Hyrax v3.4.0 to add text for collection banner image --> +<!-- OVERRIDE Hyrax v5.0.0rc2 to add text for collection banner image --> <!-- The template to display files available for upload --> <script id="template-upload" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} - <tr class="template-upload fade"> + <tr class="template-upload fade show"> <td> <span class="preview"></span> </td> @@ -38,7 +38,7 @@ <!-- The template to display the banner once upload is complete --> <script id="template-download" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} - <span class="template-download fade"> + <span class="template-download fade show"> <div id="banner"> <div class="row branding-banner-row"> <div class="col-sm-3"> @@ -47,20 +47,18 @@ <input type="hidden" name="banner_files[]" value="{%=file.id%}"> </span> {% if (file.error) { %} - <span><span class="label label-danger"><%= t('.error') %></span> {%=file.error%}</span> + <span><span class="badge badge-danger"><%= t('.error') %></span> {%=file.error%}</span> {% } %} </div> - <div class="col-sm-4 branding-banner-input"> - <label for="banner_text"><%= t('.alt_text') %> - <input id="banner_text" type="text" name="banner_text[]" class="branding-banner-input" single> - </label> + <label for="banner_text"><%= t('.alt_text') %></label> + <input id="banner_text" type="text" name="banner_text[]" class="form-control branding-banner-input" single> </div> <div class="col-sm-2"> <button class="btn btn-link remove branding-banner-remove" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}" onclick=$("#banner").remove(); {% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}> - <span class="glyphicon glyphicon-remove"></span> + <span class="fa fa-times"></span> <span class="controls-remove-text"><%= t('.remove') %></span> <span class="sr-only"> <%= t('.previous') %> @@ -77,7 +75,7 @@ <!-- The template to display logo in the table once upload is complete --> <script id="logo-template-download" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} - <span class="template-download fade"> + <span class="template-download fade show"> <div class="row branding-logo-row"> <div class="col-sm-3"> <span class="preview"> @@ -96,7 +94,7 @@ </span> {% if (file.error) { %} - <span><span class="label label-danger">Error</span> {%=file.error%}</span> + <span><span class="badge badge-danger">Error</span> {%=file.error%}</span> {% } %} </div> @@ -112,7 +110,7 @@ <div class="col-sm-2 text-right"> <span class="input-group-btn field-controls"> <button class="btn btn-sm btn-danger delete branding-logo-remove" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}> - <span class="glyphicon glyphicon-remove"></span> + <span class="fa fa-times"></span> <span class="controls-remove-text">Remove</span> <span class="sr-only"> <%= t('.previous') %> @@ -125,4 +123,4 @@ </div> </span> {% } %} -</script> \ No newline at end of file +</script> diff --git a/app/views/hyrax/users/_vitals.html.erb b/app/views/hyrax/users/_vitals.html.erb deleted file mode 100644 index a5631a8a8..000000000 --- a/app/views/hyrax/users/_vitals.html.erb +++ /dev/null @@ -1,21 +0,0 @@ -<%# override Hyrax 2.5 - fix Collections Created and Works Created links. Confirmed can be removed after Hyrax 3.0 %> -<div class="list-group-item"> - <span class="glyphicon glyphicon-time" aria-hidden="true"></span> <%= t("hyrax.dashboard.stats.joined_on") %> <%= user.created_at.to_date.strftime("%b %d, %Y") %> -</div> - -<div class="list-group-item"> - <span class="badge"><%= number_of_collections(user) %></span> - <span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span> - <%= link_to_field('', '', t("hyrax.dashboard.stats.collections"), {generic_type: "Collection", depositor: user.to_s}) %> -</div> - -<div class="list-group-item"> - <span class="badge"><%= number_of_works(user) %></span> - <span class="glyphicon glyphicon-upload" aria-hidden="true"></span> - <%= link_to_field('', '', t("hyrax.dashboard.stats.works"), {generic_type: "Work", depositor: user.to_s}) %> - - <ul class="views-downloads-dashboard list-unstyled"> - <li><span class="badge badge-optional"><%= user.total_file_views %></span> <%= t("hyrax.dashboard.stats.file_views").pluralize(user.total_file_views) %></li> - <li><span class="badge badge-optional"><%= user.total_file_downloads %></span> <%= t("hyrax.dashboard.stats.file_downloads").pluralize(user.total_file_downloads) %></li> - </ul> -</div> diff --git a/app/views/identity_providers/_form.html.erb b/app/views/identity_providers/_form.html.erb index fd2d41430..499cc0fbe 100644 --- a/app/views/identity_providers/_form.html.erb +++ b/app/views/identity_providers/_form.html.erb @@ -1,6 +1,6 @@ -<div class="panel panel-default"> - <%= simple_form_for(@identity_provider) do |f| %> - <div class="panel-body"> +<%= simple_form_for(@identity_provider) do |f| %> + <div class="card"> + <div class="card-body"> <% if @identity_provider.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@identity_provider.errors.count, "error") %> prohibited this authentication provider from being saved:</h2> @@ -11,7 +11,7 @@ </ul> </div> <% end %> - <%= f.input :name %> + <%= f.input :name, label: t('hyku.identity_provider.label.name'), required: true %> <%= f.input :provider, collection: Devise.omniauth_providers.map {|o| [o, o.upcase]}, label_method: :second, @@ -38,22 +38,21 @@ <p>Metadata is available <%= link_to 'here', "/users/auth/saml/#{@identity_provider.id}/metadata", data: { turbolinks: false } %></p> <% end %> - <%= f.input :options, input_html: {value: @identity_provider.options&.to_json } %> + <%= f.input :options, label: t('hyku.identity_provider.label.options'), input_html: {value: @identity_provider.options&.to_json } %> <%# Upload Logo Image %> - <%= f.input :logo_image, as: :file, wrapper: :vertical_file_input, hint: t('hyrax.admin.appearances.show.forms.logo_image.hint') %> - <%= f.input :logo_image_text, as: :text %> + <%= f.input :logo_image, label: t('hyku.identity_provider.label.logo_image'), as: :file, wrapper: :vertical_file_input, hint: t('hyrax.admin.appearances.show.forms.logo_image.hint') %> + <%= f.input :logo_image_text, label: t('hyku.identity_provider.label.logo_image_alt_text'), as: :text %> <%= image_tag f.object.logo_image.url(:medium), class: "img-responsive", alt: f.object.logo_image_text if f.object.logo_image? %> </div> - <div class="panel-footer text-right"> + <div class="card-footer text-right"> <% if IdentityProvider.count.nonzero? %> - <%= link_to 'Delete', identity_provider, method: :delete, data: { confirm: 'Are you sure?' }, class: - 'btn btn-danger' %> + <%= link_to 'Delete', identity_provider, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %> <% end %> <%= f.submit class: 'btn btn-primary action-save' %> </div> - <% end %> -</div> + </div> +<% end %> diff --git a/app/views/identity_providers/index.html.erb b/app/views/identity_providers/index.html.erb index 594fe23d5..80a459f93 100644 --- a/app/views/identity_providers/index.html.erb +++ b/app/views/identity_providers/index.html.erb @@ -1,18 +1,18 @@ <% content_for :page_header do %> - <h1><span class="fa fa-user"></span> <%= t(:'hyrax.admin.sidebar.identity_providers_and_permissions') %></h1> + <h1><span class="fa fa-user"></span> <%= t('hyku.identity_provider.header') %></h1> <% end %> <div class="row"> <div class="col-md-12"> - <div class="panel panel-default"> - <div class="panel-body"> + <div class="card"> + <div class="card-body"> <table class="table table-striped datatable"> <thead> <tr> - <th>Name</th> - <th>Provider</th> - <th>Updated At</th> - <th>Logo</th> + <th><%= t('hyku.identity_provider.label.name') %></th> + <th><%= t('hyku.identity_provider.label.provider') %></th> + <th><%= t('hyku.identity_provider.label.updated_at') %></th> + <th><%= t('hyku.identity_provider.label.logo') %></th> <th></th> </tr> </thead> @@ -22,14 +22,17 @@ <td><%= u.name %></td> <td><%= u.provider %></td> <td><%= u.updated_at %></td> - <td><%= image_tag u.logo_image.url(:thumb), class: "img-responsive", alt: u.logo_image_text if u.logo_image? %></td> - <td class="col-md-2"><%= link_to t('.edit'), edit_identity_provider_path(u) %> | <%= link_to t('helpers.action.delete'), identity_provider_path(u), method: :delete, data: { confirm: t('.confirm_delete') } %></td> + <td><%= image_tag u.logo_image.url(:thumb), class: "img-fluid", alt: u.logo_image_text if u.logo_image? %></td> + <td class="col-md-2"> + <%= link_to t('hyku.identity_provider.label.edit'), edit_identity_provider_path(u) %> |  + <%= link_to t('helpers.action.delete'), identity_provider_path(u), method: :delete, data: { confirm: t('.confirm_delete') } %> + </td> </tr> <% end %> </tbody> </table> <%= link_to new_identity_provider_path, class: 'btn btn-primary' do %> - <span class="fa fa-edit"></span> <%= t('.create_new') %> + <span class="fa fa-edit"></span> <%= t('hyku.identity_provider.label.create_new') %> <% end %> </div> </div> diff --git a/app/views/labels/edit.html.erb b/app/views/labels/edit.html.erb index 270c44efb..604efc337 100644 --- a/app/views/labels/edit.html.erb +++ b/app/views/labels/edit.html.erb @@ -4,40 +4,39 @@ <div class="row"> <div class="col-md-12"> - <div class="panel panel-default"> + <div class="card"> <%= form_for(@site, url: site_labels_path) do |f| %> - <div class="panel-heading"> - <h3 class="panel-title">General Repository Labels</h3> + <div class="card-header"> + <h3 class="card-title">General Repository Labels</h3> </div> - <div class="panel-body"> + <div class="card-body"> <% if @site.errors.any? %> - <div id="error_explanation"> - <h2><%= pluralize(@site.errors.count, "error") %> prohibited this site from being saved:</h2> - - <ul> - <% @site.errors.full_messages.each do |message| %> - <li><%= message %></li> - <% end %> - </ul> - </div> + <div id="error_explanation"> + <h2><%= pluralize(@site.errors.count, "error") %> prohibited this site from being saved:</h2> + <ul> + <% @site.errors.full_messages.each do |message| %> + <li><%= message %></li> + <% end %> + </ul> + </div> <% end %> <div class="field form-group"> - <%= f.label :application_name %><br> - <%= f.text_field :application_name, class: 'form-control'%> + <%= f.label :application_name %><br> + <%= f.text_field :application_name, class: 'form-control'%> </div> <div class="field form-group"> - <%= f.label :institution_name %><br> - <%= f.text_field :institution_name, class: 'form-control'%> + <%= f.label :institution_name %><br> + <%= f.text_field :institution_name, class: 'form-control'%> </div> <div class="field form-group"> - <%= f.label :institution_name_full %><br> - <%= f.text_field :institution_name_full, class: 'form-control'%> + <%= f.label :institution_name_full %><br> + <%= f.text_field :institution_name_full, class: 'form-control'%> </div> </div> - <div class="panel-footer"> - <%= f.submit class: 'btn btn-primary pull-right' %> + <div class="card-footer text-right"> + <%= f.submit class: 'btn btn-primary' %> </div> <% end %> </div> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index d6c1c0ab3..0f1c161e7 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <title>Hyku + <%= Hyku::Application.html_head_title %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> diff --git a/app/views/layouts/hyrax.html.erb b/app/views/layouts/hyrax.html.erb index e2ff69136..0387e147f 100644 --- a/app/views/layouts/hyrax.html.erb +++ b/app/views/layouts/hyrax.html.erb @@ -12,15 +12,15 @@
<%= link_to "Skip to Content", "#skip-to-content" %>
- <%= render '/masthead' %> + <%= render '/masthead', placement_class: nil %> <%= content_for(:navbar) %> <%= content_for(:precontainer_content) %>
<%= render '/flash_msg' %> - <%= render_breadcrumbs builder: Hyrax::BootstrapBreadcrumbsBuilder %> + <%= render_breadcrumbs builder: Hyrax.config.breadcrumb_builder %> <% if content_for?(:page_header) %>
-
+
<%= yield(:page_header) %>
@@ -31,6 +31,6 @@ <%= content_for?(:content) ? yield(:content) : yield %>
<%= render 'shared/footer' %> - <%= render 'shared/ajax_modal' %> + <%= render 'shared/modal' %> diff --git a/app/views/proprietor/accounts/edit.html.erb b/app/views/proprietor/accounts/edit.html.erb index 56b82d6ad..b835d66a1 100644 --- a/app/views/proprietor/accounts/edit.html.erb +++ b/app/views/proprietor/accounts/edit.html.erb @@ -4,9 +4,9 @@
-