diff --git a/.rubocop_fixme.yml b/.rubocop_fixme.yml index a51fe2641b..e86d00e2bd 100644 --- a/.rubocop_fixme.yml +++ b/.rubocop_fixme.yml @@ -152,3 +152,35 @@ RSpec/AnyInstance: - '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' + +# Offense count: 51 +RSpec/ExpectInHook: + Enabled: false + +# Offense count: 31 +RSpec/LetBeforeExamples: + Exclude: + - 'spec/forms/hyrax/forms/collection_form_spec.rb' + - 'spec/presenters/hyrax/collection_presenter_spec.rb' + - 'spec/presenters/hyrax/trophy_presenter_spec.rb' + - 'spec/services/hyrax/query_service_spec.rb' + - 'spec/services/hyrax/workflow/action_taken_service_spec.rb' + - 'spec/services/hyrax/workflow/notification_service_spec.rb' + +# 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' diff --git a/README.md b/README.md index d34f75b6b0..6a1a0ac908 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ The Samvera community is here to help. Please see our [support guide](./.github/ # Getting started This document contains instructions specific to setting up an app with __Hyrax -v2.0.0.beta2__. If you are looking for instructions on installing a different +v2.0.0.beta3__. If you are looking for instructions on installing a different version, be sure to select the appropriate branch or tag from the drop-down menu above. @@ -160,7 +160,7 @@ NOTE: The steps need to be done in order to create a new Hyrax based app. Generate a new Rails application using the template. ``` -rails _5.0.5_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.0.0.beta2/template.rb +rails _5.0.5_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.0.0.beta3/template.rb ``` Generating a new Rails application using Hyrax's template above takes cares of a number of steps for you, including: diff --git a/app/assets/javascripts/hyrax/app.js.erb b/app/assets/javascripts/hyrax/app.js.erb index e37f91a75b..5bd25e8591 100644 --- a/app/assets/javascripts/hyrax/app.js.erb +++ b/app/assets/javascripts/hyrax/app.js.erb @@ -103,6 +103,10 @@ Hyrax = { // ActionCable for user notifications. This is displayed in the navbar. notifications: function() { + // Do not create a consumer if user is not logged in + if ($("meta[name='current-user']").length === 0) + return; + <% if Hyrax.config.realtime_notifications? %> var consumer = ActionCable.createConsumer("<%= Hyrax::Engine.routes.url_helpers.notifications_endpoint_path %>"); consumer.subscriptions.create("Hyrax::NotificationsChannel", { connected: function(data) { @@ -114,6 +118,7 @@ Hyrax = { new Notification($('.notify-number')).update(data.notifications_count, data.notifications_label); } }); + <% end %> }, // Search for a user to transfer a work to diff --git a/app/assets/javascripts/hyrax/channels/notifications.js b/app/assets/javascripts/hyrax/channels/notifications.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/app/controllers/hyrax/citations_controller.rb b/app/controllers/hyrax/citations_controller.rb index 2522e0a918..5dbf70ef99 100644 --- a/app/controllers/hyrax/citations_controller.rb +++ b/app/controllers/hyrax/citations_controller.rb @@ -4,6 +4,7 @@ class CitationsController < ApplicationController include Breadcrumbs include SingularSubresourceController + layout :decide_layout before_action :build_breadcrumbs, only: [:work, :file] def work @@ -24,5 +25,16 @@ def file def show_presenter WorkShowPresenter end + + def decide_layout + case action_name + when 'work', 'file' + theme + else + # Not currently used in this controller, but left here to + # support dashboard-based work views which are ticketed + 'dashboard' + end + end end end diff --git a/app/jobs/stream_notifications_job.rb b/app/jobs/stream_notifications_job.rb index 822729fc81..0c0773a396 100644 --- a/app/jobs/stream_notifications_job.rb +++ b/app/jobs/stream_notifications_job.rb @@ -1,5 +1,7 @@ class StreamNotificationsJob < Hyrax::ApplicationJob def perform(users) + # Do not use the ActionCable machinery if the feature is disabled + return unless Hyrax.config.realtime_notifications? Array.wrap(users).each do |user| mailbox = UserMailbox.new(user) Hyrax::NotificationsChannel.broadcast_to(user, diff --git a/app/services/hyrax/curation_concern.rb b/app/services/hyrax/curation_concern.rb index 8a7f1d9163..8b31fbc197 100644 --- a/app/services/hyrax/curation_concern.rb +++ b/app/services/hyrax/curation_concern.rb @@ -17,7 +17,7 @@ class CurationConcern # is used. Once it is used, it becomes immutable. # @return [ActionDispatch::MiddlewareStack] def self.actor_factory - Hyrax::DefaultMiddlewareStack.build_stack + @actor_factory ||= Hyrax::DefaultMiddlewareStack.build_stack end # A consumer of this method can inject a different factory diff --git a/app/views/layouts/_head_tag_content.html.erb b/app/views/layouts/_head_tag_content.html.erb index 88a2b49a05..29a404e97a 100644 --- a/app/views/layouts/_head_tag_content.html.erb +++ b/app/views/layouts/_head_tag_content.html.erb @@ -1,6 +1,11 @@ <%= csrf_meta_tag %> - +<%# Only display meta tag, which enables creation of the ActionCable +consumer, when realtime notifications are enabled and the user is +signed in %> +<% if Hyrax.config.realtime_notifications? && signed_in? %> + <%= tag :meta, name: 'current-user', data: { user_key: current_user.user_key } %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index ef53d1c872..81e14faa00 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -92,9 +92,11 @@ delete 'delete_all' end end - namespace :notifications do - # WebSocket for notifications - mount ActionCable.server => 'endpoint', as: :endpoint + if Hyrax.config.realtime_notifications? + namespace :notifications do + # WebSocket for notifications + mount ActionCable.server => 'endpoint', as: :endpoint + end end # User profile diff --git a/hyrax.gemspec b/hyrax.gemspec index f054a89165..ecd21cdd71 100644 --- a/hyrax.gemspec +++ b/hyrax.gemspec @@ -40,8 +40,8 @@ EOF spec.add_dependency 'blacklight-gallery', '~> 0.7' spec.add_dependency 'tinymce-rails', '~> 4.1' spec.add_dependency 'font-awesome-rails', '~> 4.2' - spec.add_dependency 'select2-rails', '~> 3.5.9' - spec.add_dependency 'json-schema' # for Arkivio + spec.add_dependency 'select2-rails', '~> 3.5' + spec.add_dependency 'json-schema' # for Arkivo spec.add_dependency 'nest', '~> 2.0' spec.add_dependency 'mailboxer', '~> 0.12' spec.add_dependency 'carrierwave', '~> 1.0' @@ -51,18 +51,20 @@ EOF spec.add_dependency 'legato', '~> 0.3' spec.add_dependency 'posix-spawn' spec.add_dependency 'jquery-ui-rails', '~> 5.0' - spec.add_dependency 'redis-namespace', '~> 1.5.2' + spec.add_dependency 'redis-namespace', '~> 1.5' + # Pin more tightly because 0.x gems are potentially unstable spec.add_dependency 'flot-rails', '~> 0.0.6' spec.add_dependency 'almond-rails', '~> 0.1' spec.add_dependency 'qa', '~> 1.0' # questioning_authority spec.add_dependency 'flipflop', '~> 2.3' - spec.add_dependency 'jquery-datatables-rails', '~> 3.4.0' + spec.add_dependency 'jquery-datatables-rails', '~> 3.4' spec.add_dependency 'rdf-rdfxml' # controlled vocabulary importer spec.add_dependency 'clipboard-rails', '~> 1.5' spec.add_dependency 'rails_autolink', '~> 1.1' spec.add_dependency 'active_fedora-noid', '~> 2.0', '>= 2.0.2' spec.add_dependency 'awesome_nested_set', '~> 3.1' spec.add_dependency 'breadcrumbs_on_rails', '~> 3.0' + # Pin more tightly because 0.x gems are potentially unstable spec.add_dependency 'kaminari_route_prefix', '~> 0.1.1' spec.add_dependency 'power_converter', '~> 0.1', '>= 0.1.2' spec.add_dependency 'dry-validation', '~> 0.9' @@ -89,8 +91,18 @@ EOF spec.add_development_dependency "factory_girl_rails", '~> 4.4' spec.add_development_dependency "equivalent-xml", '~> 0.5' spec.add_development_dependency "jasmine", '~> 2.3' + # Pin rubocop and rubocop-rspec tightly. Minor-level version bumps + # in these gems cause Rubocop violations, and those violations cause + # continuous integration builds to fail, and those failures prevent + # us from merging pull requests. As a community, we have decided + # that it is not reasonable to manage style violations to be dealt + # with in a pull request *unless* said pull request's intent is to + # bring the codebase in further alignment with community style + # conventions. This allows us to take a managed approach to code + # style -- we choose to update style when we wish, not when a + # minor-level version bump in a dependency comes out. spec.add_development_dependency 'rubocop', '~> 0.49.1' - spec.add_development_dependency 'rubocop-rspec', '~> 1.15.0' + spec.add_development_dependency 'rubocop-rspec', '~> 1.16.0' spec.add_development_dependency 'shoulda-matchers', '~> 3.1' spec.add_development_dependency 'rails-controller-testing', '~> 0' spec.add_development_dependency 'webmock' diff --git a/lib/generators/hyrax/templates/config/hyrax.rb b/lib/generators/hyrax/templates/config/hyrax.rb index 1cc439b46f..e3480e737e 100644 --- a/lib/generators/hyrax/templates/config/hyrax.rb +++ b/lib/generators/hyrax/templates/config/hyrax.rb @@ -89,6 +89,9 @@ # of Zotero-managed research items. # config.arkivo_api = false + # Stream realtime notifications to users in the browser + # config.realtime_notifications = true + # Location autocomplete uses geonames to search for named regions # Username for connecting to geonames # config.geonames_username = '' diff --git a/lib/hyrax/configuration.rb b/lib/hyrax/configuration.rb index 9e4f0beba5..5db832fa67 100644 --- a/lib/hyrax/configuration.rb +++ b/lib/hyrax/configuration.rb @@ -279,6 +279,22 @@ def arkivo_api? @arkivo_api ||= false end + # rubocop:disable Metrics/LineLength + attr_writer :realtime_notifications + def realtime_notifications? + # Coerce @realtime_notifications to false if server software + # does not support WebSockets, and warn the user that we are + # overriding the value in their config unless it's already + # flipped to false + if ENV.fetch('SERVER_SOFTWARE', '').match(/Apache.*Phusion_Passenger/).present? + Rails.logger.warn('Cannot enable realtime notifications atop Passenger + Apache. Coercing `Hyrax.config.realtime_notifications` to `false`. Set this value to `false` in config/initializers/hyrax.rb to stop seeing this warning.') unless @realtime_notifications == false + @realtime_notifications = false + end + return @realtime_notifications unless @realtime_notifications.nil? + @realtime_notifications = true + end + # rubocop:enable Metrics/LineLength + def geonames_username=(username) Qa::Authorities::Geonames.username = username end diff --git a/lib/hyrax/version.rb b/lib/hyrax/version.rb index 774d628324..f3023c2334 100644 --- a/lib/hyrax/version.rb +++ b/lib/hyrax/version.rb @@ -1,3 +1,3 @@ module Hyrax - VERSION = '2.0.0.beta2'.freeze + VERSION = '2.0.0.beta3'.freeze end diff --git a/solr/config/schema.xml b/solr/config/schema.xml index 2e9deac632..8eda5703de 100644 --- a/solr/config/schema.xml +++ b/solr/config/schema.xml @@ -334,12 +334,6 @@ --> id - - - - - - diff --git a/spec/controllers/hyrax/citations_controller_spec.rb b/spec/controllers/hyrax/citations_controller_spec.rb index fab85e62fc..be301c5f7f 100644 --- a/spec/controllers/hyrax/citations_controller_spec.rb +++ b/spec/controllers/hyrax/citations_controller_spec.rb @@ -14,6 +14,7 @@ expect(controller).to receive(:add_breadcrumb).with('My Dashboard', Hyrax::Engine.routes.url_helpers.dashboard_path(locale: 'en')) get :work, params: { id: work } expect(response).to be_successful + expect(response).to render_template('layouts/hyrax') expect(assigns(:presenter)).to be_kind_of Hyrax::WorkShowPresenter end end @@ -41,6 +42,7 @@ expect(controller).to receive(:add_breadcrumb).with('My Dashboard', Hyrax::Engine.routes.url_helpers.dashboard_path(locale: 'en')) get :file, params: { id: file_set } expect(response).to be_successful + expect(response).to render_template('layouts/hyrax') expect(assigns(:presenter)).to be_kind_of Hyrax::FileSetPresenter end end diff --git a/spec/jobs/stream_notifications_job_spec.rb b/spec/jobs/stream_notifications_job_spec.rb index 697008bdc4..46d43703a3 100644 --- a/spec/jobs/stream_notifications_job_spec.rb +++ b/spec/jobs/stream_notifications_job_spec.rb @@ -1,4 +1,10 @@ RSpec.describe StreamNotificationsJob do + let(:realtime_notifications) { true } + + before do + allow(Hyrax.config).to receive(:realtime_notifications?).and_return(realtime_notifications) + end + describe '#perform' do context 'with zero users' do let(:users) { nil } @@ -25,6 +31,15 @@ notifications_label: "You've got mail!") described_class.perform_now(users) end + + context 'when realtime notifications feature is disabled' do + let(:realtime_notifications) { false } + + it 'does not broadcast' do + expect(Hyrax::NotificationsChannel).not_to receive(:broadcast_to) + described_class.perform_now(users) + end + end end end end diff --git a/spec/lib/hyrax/configuration_spec.rb b/spec/lib/hyrax/configuration_spec.rb index 01315a1824..bb27f5c236 100644 --- a/spec/lib/hyrax/configuration_spec.rb +++ b/spec/lib/hyrax/configuration_spec.rb @@ -50,6 +50,8 @@ it { is_expected.to respond_to(:permission_levels) } it { is_expected.to respond_to(:permission_options) } it { is_expected.to respond_to(:persistent_hostpath) } + it { is_expected.to respond_to(:realtime_notifications?) } + it { is_expected.to respond_to(:realtime_notifications=) } it { is_expected.to respond_to(:redis_namespace) } it { is_expected.to respond_to(:subject_prefix) } it { is_expected.to respond_to(:translate_id_to_uri) } diff --git a/spec/services/hyrax/curation_concern_spec.rb b/spec/services/hyrax/curation_concern_spec.rb index 36b6a4b7b4..a45fdbcde5 100644 --- a/spec/services/hyrax/curation_concern_spec.rb +++ b/spec/services/hyrax/curation_concern_spec.rb @@ -7,4 +7,12 @@ it { is_expected.to be_kind_of Hyrax::Actors::TransactionalRequest } end + + describe ".actor_factory" do + subject { described_class.actor_factory } + + it "returns same ActionDispatch::MiddlewareStack instance" do + is_expected.to eq described_class.actor_factory + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01d0529fd0..668a75429d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -142,7 +142,7 @@ def main_app Hyrax.config.enable_noids = false end - config.before :each do |example| + config.before do |example| if example.metadata[:type] == :feature && Capybara.current_driver != :rack_test DatabaseCleaner.strategy = :truncation else diff --git a/spec/tasks/rake_spec.rb b/spec/tasks/rake_spec.rb index b3a33742e5..5b2cf09e77 100644 --- a/spec/tasks/rake_spec.rb +++ b/spec/tasks/rake_spec.rb @@ -11,15 +11,15 @@ it "creates a file" do run_task "hyrax:user:list_emails" - expect(File.exist?("user_emails.txt")).to be_truthy + expect(File).to exist("user_emails.txt") expect(IO.read("user_emails.txt")).to include(user1.email, user2.email) File.delete("user_emails.txt") end it "creates a file I give it" do run_task "hyrax:user:list_emails", "abc123.txt" - expect(File.exist?("user_emails.txt")).not_to be_truthy - expect(File.exist?("abc123.txt")).to be_truthy + expect(File).not_to exist("user_emails.txt") + expect(File).to exist("abc123.txt") expect(IO.read("abc123.txt")).to include(user1.email, user2.email) File.delete("abc123.txt") end diff --git a/spec/views/hyrax/base/show.html.erb_spec.rb b/spec/views/hyrax/base/show.html.erb_spec.rb index 6e2957e232..dab12cb721 100644 --- a/spec/views/hyrax/base/show.html.erb_spec.rb +++ b/spec/views/hyrax/base/show.html.erb_spec.rb @@ -49,6 +49,7 @@ allow(controller).to receive(:current_user).and_return(depositor) allow(User).to receive(:find_by_user_key).and_return(depositor.user_key) allow(view).to receive(:blacklight_config).and_return(Blacklight::Configuration.new) + allow(view).to receive(:signed_in?) allow(view).to receive(:on_the_dashboard?).and_return(false) stub_template 'hyrax/base/_metadata.html.erb' => '' stub_template 'hyrax/base/_relationships.html.erb' => '' diff --git a/spec/views/hyrax/homepage/index.html.erb_spec.rb b/spec/views/hyrax/homepage/index.html.erb_spec.rb index 8ab8d9aac9..bee96e7737 100644 --- a/spec/views/hyrax/homepage/index.html.erb_spec.rb +++ b/spec/views/hyrax/homepage/index.html.erb_spec.rb @@ -4,15 +4,59 @@ let(:presenter) { instance_double(Hyrax::HomepagePresenter) } let(:type_presenter) { instance_double(Hyrax::SelectTypeListPresenter, many?: true) } - describe "share your work button" do + before do + allow(view).to receive(:create_work_presenter).and_return(type_presenter) + allow(view).to receive(:signed_in?).and_return(signed_in) + allow(controller).to receive(:current_ability).and_return(ability) + assign(:presenter, presenter) + stub_template "hyrax/homepage/_marketing.html.erb" => "marketing" + stub_template "hyrax/homepage/_home_content.html.erb" => "home content" + end + + describe 'meta tag with current user info' do + let(:realtime_notifications) { true } + before do - allow(view).to receive(:create_work_presenter).and_return(type_presenter) - allow(view).to receive(:signed_in?).and_return(signed_in) - assign(:presenter, presenter) + allow(Hyrax.config).to receive(:realtime_notifications?).and_return(realtime_notifications) + allow(view).to receive(:on_the_dashboard?).and_return(false) + allow(controller).to receive(:current_user).and_return(current_user) allow(controller).to receive(:current_ability).and_return(ability) + allow(presenter).to receive(:display_share_button?).and_return(true) + stub_template "_controls.html.erb" => "controls" + stub_template "_masthead.html.erb" => "masthead" + render template: 'hyrax/homepage/index', layout: 'layouts/homepage' + end + + context 'when signed in' do + let(:signed_in) { true } + let(:current_user) { create(:user) } + + it 'renders' do + expect(rendered).to have_selector('meta[name="current-user"]', visible: false) + end + + context 'when realtime notifications are disabled' do + let(:realtime_notifications) { false } + + it 'does not render' do + expect(rendered).not_to have_selector('meta[name="current-user"]', visible: false) + end + end + end + + context 'when not signed in' do + let(:signed_in) { false } + let(:current_user) { nil } + + it 'does not render' do + expect(rendered).not_to have_selector('meta[name="current-user"]', visible: false) + end + end + end + + describe "share your work button" do + before do allow(presenter).to receive(:display_share_button?).and_return(display_share_button) - stub_template "hyrax/homepage/_marketing.html.erb" => "marketing" - stub_template "hyrax/homepage/_home_content.html.erb" => "home content" render end diff --git a/spec/views/pages/show.html.erb_spec.rb b/spec/views/pages/show.html.erb_spec.rb index d6adc39af4..8732b09b86 100644 --- a/spec/views/pages/show.html.erb_spec.rb +++ b/spec/views/pages/show.html.erb_spec.rb @@ -3,6 +3,7 @@ before do assign(:page, content_block) + allow(view).to receive(:signed_in?) allow(view).to receive(:displayable_content_block) allow(view).to receive(:can?).and_return(false) stub_template 'catalog/_search_form.html.erb' => '' diff --git a/template.rb b/template.rb index 034ffad4ca..19bd226559 100644 --- a/template.rb +++ b/template.rb @@ -1,4 +1,4 @@ -gem 'hyrax', '2.0.0.beta2' +gem 'hyrax', '2.0.0.beta3' run 'bundle install' generate 'hyrax:install', '-f' rails_command 'db:migrate'