diff --git a/.rubocop_fixme.yml b/.rubocop_fixme.yml index fb52bcc4db..e11a79b74b 100644 --- a/.rubocop_fixme.yml +++ b/.rubocop_fixme.yml @@ -165,7 +165,6 @@ RSpec/LetBeforeExamples: - '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' diff --git a/.travis.yml b/.travis.yml index 66229106ee..fd27e72532 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,18 +13,19 @@ before_install: - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost & rvm: - - 2.4.1 + - 2.4.2 env: global: - NOKOGIRI_USE_SYSTEM_LIBRARIES=true + - ENGINE_CART_RAILS_OPTIONS='--skip-git --skip-bundle --skip-listen --skip-spring --skip-yarn --skip-keeps --skip-action-cable --skip-coffee --skip-puma --skip-test' # Travis should check every minor version in a range of supported versions, because # rails does not follow sem-ver conventions, see http://guides.rubyonrails.org/maintenance_policy.html # It should be sufficient to test only the latest of the patch versions for a minor version, they # should be compatible across patch versions (only bug fixes are released in patch versions). matrix: - - "RAILS_VERSION=5.0.6" - "RAILS_VERSION=5.1.4" + - "RAILS_VERSION=5.0.6" services: - redis-server diff --git a/README.md b/README.md index 4778695763..89e981391a 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Docs: [![Documentation Status](https://inch-ci.org/github/samvera/hyrax.svg?bran [![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE) Jump in: [![Slack Status](http://slack.samvera.org/badge.svg)](http://slack.samvera.org/) -[![Ready Tickets](https://badge.waffle.io/samvera/hyrax.png?label=ready&milestone=2.0.0&title=Ready)](https://waffle.io/samvera/hyrax?milestone=2.0.0) +[![Ready Tickets](https://badge.waffle.io/samvera/hyrax.png?label=ready&milestone=2.x%20series&title=Ready)](https://waffle.io/samvera/hyrax?milestone=2.x%20series) # Table of Contents @@ -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.beta4__. If you are looking for instructions on installing a different +v2.0.0.rc1__. 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.6_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.0.0.beta4/template.rb +rails _5.0.6_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.0.0.rc1/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/actors/hyrax/actors/create_with_remote_files_actor.rb b/app/actors/hyrax/actors/create_with_remote_files_actor.rb index 7f79768998..50f1f1ba6c 100644 --- a/app/actors/hyrax/actors/create_with_remote_files_actor.rb +++ b/app/actors/hyrax/actors/create_with_remote_files_actor.rb @@ -18,12 +18,34 @@ def update(env) private + def whitelisted_ingest_dirs + Hyrax.config.whitelisted_ingest_dirs + end + + def validate_remote_url(url) + uri = URI.parse(URI.encode(url)) + if uri.scheme == 'file' + path = File.absolute_path(URI.decode(uri.path)) + whitelisted_ingest_dirs.any? do |dir| + path.start_with?(dir) && path.length > dir.length + end + else + # TODO: It might be a good idea to validate other URLs as well. + # The server can probably access URLs the user can't. + true + end + end + # @param [HashWithIndifferentAccess] remote_files # @return [TrueClass] def attach_files(env, remote_files) return true unless remote_files remote_files.each do |file_info| next if file_info.blank? || file_info[:url].blank? + unless validate_remote_url(file_info[:url]) + Rails.logger.error "User #{env.user.user_key} attempted to ingest file from url #{file_info[:url]}, which doesn't pass validation" + return false + end create_file_from_url(env, file_info[:url], file_info[:file_name]) end true diff --git a/app/actors/hyrax/actors/transfer_request_actor.rb b/app/actors/hyrax/actors/transfer_request_actor.rb new file mode 100644 index 0000000000..1219767530 --- /dev/null +++ b/app/actors/hyrax/actors/transfer_request_actor.rb @@ -0,0 +1,23 @@ +module Hyrax + module Actors + # Notify the provided owner that their proxy wants to make a + # deposit on their behalf + class TransferRequestActor < AbstractActor + # @param [Hyrax::Actors::Environment] env + # @return [Boolean] true if create was successful + def create(env) + next_actor.create(env) && create_proxy_deposit_request(env) + end + + private + + def create_proxy_deposit_request(env) + proxy = env.curation_concern.on_behalf_of + return true if proxy.blank? + ContentDepositorChangeEventJob.perform_later(env.curation_concern, + ::User.find_by_user_key(proxy)) + true + end + end + end +end diff --git a/app/assets/javascripts/hyrax/save_work/visibility_component.es6 b/app/assets/javascripts/hyrax/save_work/visibility_component.es6 index 1225e1af03..841d16d9a0 100644 --- a/app/assets/javascripts/hyrax/save_work/visibility_component.es6 +++ b/app/assets/javascripts/hyrax/save_work/visibility_component.es6 @@ -76,14 +76,9 @@ export default class VisibilityComponent { // Apply visibility/release restrictions based on selected AdminSet applyRestrictions(visibility, release_no_delay, release_date, release_before) { - // If immediate release required and visibility specified - if(release_no_delay && visibility) { - // Select required visibility - this.selectVisibility(visibility) - } - else if(release_no_delay) { - // No visibility required, but must be released today. Disable embargo & lease. - this.disableEmbargoAndLease(); + // If immediate release required or the release date is in the past. + if(release_no_delay || (release_date && (new Date() > Date.parse(release_date)))) { + this.requireReleaseNow(visibility) } // Otherwise if future date and release_before==true, must be released between today and release_date else if(release_date && release_before) { @@ -137,6 +132,18 @@ export default class VisibilityComponent { this.selectVisibilityAfterEmbargo(visibility) } + // Require release now + requireReleaseNow(visibility) { + if(visibility) { + // Select required visibility + this.selectVisibility(visibility) + } + else { + // No visibility required, but must be released today. Disable embargo & lease. + this.disableEmbargoAndLease() + } + } + // Disable Embargo and Lease options. Work must be released immediately disableEmbargoAndLease() { this.disableVisibilityOptions(["embargo","lease"]) @@ -153,6 +160,8 @@ export default class VisibilityComponent { this.element.find(matchEnabled).prop("disabled", false) } this.element.find(matchDisabled).prop("disabled", true) + + this.checkEnabledVisibilityOption() } // Disable one or more visibility option (based on array of passed in options), @@ -166,6 +175,8 @@ export default class VisibilityComponent { this.element.find(matchDisabled).prop("disabled", true) } this.element.find(matchEnabled).prop("disabled", false) + + this.checkEnabledVisibilityOption() } // Create a jQuery matcher which will match for all the specified options @@ -255,6 +266,16 @@ export default class VisibilityComponent { return this.element.find("select[id$='_visibility_after_embargo']") } + // If the selected visibility option is disabled change selection to the + // least public option that is enabled. + checkEnabledVisibilityOption() { + if (this.element.find("[type='radio']:disabled:checked").length > 0) { + this.element.find("[type='radio']:enabled").last().prop('checked', true) + // Ensure required option is opened in form + this.showForm() + } + } + // Get today's date in YYYY-MM-DD format getToday() { let today = new Date() diff --git a/app/forms/hyrax/forms/permission_template_form.rb b/app/forms/hyrax/forms/permission_template_form.rb index bb1e45d79a..01e94ddb31 100644 --- a/app/forms/hyrax/forms/permission_template_form.rb +++ b/app/forms/hyrax/forms/permission_template_form.rb @@ -186,6 +186,8 @@ def select_release_varies_option(permission_template) # Removes release_varies and release_embargo from the returned attributes # These form fields are only used to update release_period # @return [Hash] attributes used to update the model + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/PerceivedComplexity def permission_template_update_params(raw_attributes) attributes = raw_attributes.except(:release_varies, :release_embargo) # If 'varies' before date option selected, then set release_period='before' and save release_date as-is @@ -199,19 +201,21 @@ def permission_template_update_params(raw_attributes) attributes[:release_date] = nil end - if attributes[:release_period] == Hyrax::PermissionTemplate::RELEASE_TEXT_VALUE_NO_DELAY - # If release is "no delay", a release_date should never be allowed/specified + if attributes[:release_period] == Hyrax::PermissionTemplate::RELEASE_TEXT_VALUE_NO_DELAY || (attributes[:release_period].blank? && raw_attributes[:release_varies].blank?) + # If release is "no delay" or is "varies" and "allow depositor to decide", + # then a release_date should never be allowed/specified attributes[:release_date] = nil end attributes end + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/PerceivedComplexity # validate the hash of attributes used to update the visibility tab of the model # @param [Hash] attributes # @return [String, Nil] the error code if invalid, nil if valid # rubocop:disable Metrics/CyclomaticComplexity - # rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/PerceivedComplexity def validate_visibility_combinations(attributes) return unless attributes.key?(:visibility) # only the visibility tab has validations @@ -219,9 +223,6 @@ def validate_visibility_combinations(attributes) # if "save" without any selections - none of the attributes are present return "nothing" if !attributes[:release_varies] && !attributes[:release_period] && !attributes[:release_date] && !attributes[:release_embargo] - # if "varies" without sub-options (in this case, release_varies will be missing) - return "varies" if attributes[:release_period].blank? && attributes[:release_varies].blank? - # if "varies before" but date not selected return "no_date" if attributes[:release_varies] == Hyrax::PermissionTemplate::RELEASE_TEXT_VALUE_BEFORE_DATE && attributes[:release_date].blank? @@ -233,7 +234,6 @@ def validate_visibility_combinations(attributes) end # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/PerceivedComplexity - # rubocop:enable Metrics/AbcSize end end end diff --git a/app/helpers/hyrax/hyrax_helper_behavior.rb b/app/helpers/hyrax/hyrax_helper_behavior.rb index 45a6a1ac6b..a9171fe474 100644 --- a/app/helpers/hyrax/hyrax_helper_behavior.rb +++ b/app/helpers/hyrax/hyrax_helper_behavior.rb @@ -1,5 +1,3 @@ -# coding: utf-8 - module Hyrax module HyraxHelperBehavior include Hyrax::CitationsBehavior @@ -198,13 +196,21 @@ def link_to_profile(args) end # A Blacklight index field helper_method - # @param [Hash] options from blacklight helper_method invocation. Maps rights URIs to links with labels. - # @return [ActiveSupport::SafeBuffer] rights statement links, html_safe + # @param [Hash] options from blacklight helper_method invocation. Maps license URIs to links with labels. + # @return [ActiveSupport::SafeBuffer] license links, html_safe def license_links(options) service = Hyrax::LicenseService.new options[:value].map { |right| link_to service.label(right), right }.to_sentence.html_safe end + # A Blacklight index field helper_method + # @param [Hash] options from blacklight helper_method invocation. Maps rights statement URIs to links with labels. + # @return [ActiveSupport::SafeBuffer] rights statement links, html_safe + def rights_statement_links(options) + service = Hyrax::RightsStatementService.new + options[:value].map { |right| link_to service.label(right), right }.to_sentence.html_safe + end + def link_to_telephone(user) return unless user link_to user.telephone, "wtai://wp/mc;#{user.telephone}" if user.telephone diff --git a/app/models/concerns/hyrax/proxy_deposit.rb b/app/models/concerns/hyrax/proxy_deposit.rb index aefda2fee5..d0014036ca 100644 --- a/app/models/concerns/hyrax/proxy_deposit.rb +++ b/app/models/concerns/hyrax/proxy_deposit.rb @@ -11,14 +11,6 @@ module ProxyDeposit property :on_behalf_of, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#onBehalfOf'), multiple: false do |index| index.as :symbol end - - after_create :create_transfer_request - end - - def create_transfer_request - return if on_behalf_of.blank? - ContentDepositorChangeEventJob.perform_later(self, - ::User.find_by_user_key(on_behalf_of)) end def request_transfer_to(target) diff --git a/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb b/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb new file mode 100644 index 0000000000..90ff31c447 --- /dev/null +++ b/app/renderers/hyrax/renderers/rights_statement_attribute_renderer.rb @@ -0,0 +1,25 @@ +module Hyrax + module Renderers + # This is used by PresentsAttributes to show licenses + # e.g.: presenter.attribute_to_html(:rights_statement, render_as: :rights_statement) + class RightsStatementAttributeRenderer < AttributeRenderer + private + + ## + # Special treatment for license/rights. A URL from the Hyrax gem's config/hyrax.rb is stored in the descMetadata of the + # curation_concern. If that URL is valid in form, then it is used as a link. If it is not valid, it is used as plain text. + def attribute_value_to_html(value) + begin + parsed_uri = URI.parse(value) + rescue + nil + end + if parsed_uri.nil? + ERB::Util.h(value) + else + %(#{Hyrax.config.rights_statement_service_class.new.label(value)}) + end + end + end + end +end diff --git a/app/services/hyrax/default_middleware_stack.rb b/app/services/hyrax/default_middleware_stack.rb index f09e945cca..386245c84c 100644 --- a/app/services/hyrax/default_middleware_stack.rb +++ b/app/services/hyrax/default_middleware_stack.rb @@ -13,6 +13,7 @@ def self.build_stack middleware.use Hyrax::Actors::AttachMembersActor middleware.use Hyrax::Actors::ApplyOrderActor middleware.use Hyrax::Actors::InterpretVisibilityActor + middleware.use Hyrax::Actors::TransferRequestActor middleware.use Hyrax::Actors::DefaultAdminSetActor middleware.use Hyrax::Actors::ApplyPermissionTemplateActor middleware.use Hyrax::Actors::CleanupFileSetsActor diff --git a/app/services/hyrax/query_service.rb b/app/services/hyrax/query_service.rb deleted file mode 100644 index 28c2c9be10..0000000000 --- a/app/services/hyrax/query_service.rb +++ /dev/null @@ -1,53 +0,0 @@ -module Hyrax - class QueryService - # query to find works created during the time range - # @param [DateTime] start_datetime starting date time for range query - # @param [DateTime] end_datetime ending date time for range query - def find_by_date_created(start_datetime, end_datetime = nil) - return [] if start_datetime.blank? # no date just return nothing - relation.where(build_date_query(start_datetime, end_datetime)) - end - - def find_registered_in_date_range(start_datetime, end_datetime = nil) - find_by_date_created(start_datetime, end_datetime).merge(where_registered) - end - - def find_public_in_date_range(start_datetime, end_datetime = nil) - find_by_date_created(start_datetime, end_datetime).merge(where_public) - end - - def where_public - where_access_is 'public' - end - - def where_registered - where_access_is 'registered' - end - - def build_date_query(start_datetime, end_datetime) - start_date_str = start_datetime.utc.strftime(date_format) - end_date_str = if end_datetime.blank? - "*" - else - end_datetime.utc.strftime(date_format) - end - "system_create_dtsi:[#{start_date_str} TO #{end_date_str}]" - end - - delegate :count, to: :relation - - def relation - Hyrax::WorkRelation.new - end - - private - - def where_access_is(access_level) - relation.where Hydra.config.permissions.read.group => access_level - end - - def date_format - "%Y-%m-%dT%H:%M:%SZ" - end - end -end diff --git a/app/services/hyrax/rights_statements.rb b/app/services/hyrax/rights_statement_service.rb similarity index 75% rename from app/services/hyrax/rights_statements.rb rename to app/services/hyrax/rights_statement_service.rb index 39fb1138b4..c6cfcfef9e 100644 --- a/app/services/hyrax/rights_statements.rb +++ b/app/services/hyrax/rights_statement_service.rb @@ -1,6 +1,6 @@ module Hyrax # Provide select options for the copyright status (edm:rights) field - class RightsStatements < QaSelectService + class RightsStatementService < QaSelectService def initialize super('rights_statements') end diff --git a/app/services/hyrax/statistics/depositors/summary.rb b/app/services/hyrax/statistics/depositors/summary.rb index c0853188c0..dc5ea8ee4f 100644 --- a/app/services/hyrax/statistics/depositors/summary.rb +++ b/app/services/hyrax/statistics/depositors/summary.rb @@ -55,7 +55,11 @@ def query end def date_query - Hyrax::QueryService.new.build_date_query(start_dt, end_dt) if start_dt.present? + query_service.build_date_query(start_dt, end_dt) if start_dt.present? + end + + def query_service + Hyrax::Statistics::QueryService.new end end end diff --git a/app/services/hyrax/statistics/over_time.rb b/app/services/hyrax/statistics/over_time.rb index fe56b45c3d..f280c630dc 100644 --- a/app/services/hyrax/statistics/over_time.rb +++ b/app/services/hyrax/statistics/over_time.rb @@ -35,7 +35,11 @@ def point(min, max) end def query(min, max) - QueryService.new.build_date_query(min, max) + query_service.build_date_query(min, max) + end + + def query_service + Hyrax::Statistics::QueryService.new end # How many points are in this data set diff --git a/app/services/hyrax/statistics/query_service.rb b/app/services/hyrax/statistics/query_service.rb new file mode 100644 index 0000000000..56aef7725f --- /dev/null +++ b/app/services/hyrax/statistics/query_service.rb @@ -0,0 +1,55 @@ +module Hyrax + module Statistics + class QueryService + # query to find works created during the time range + # @param [DateTime] start_datetime starting date time for range query + # @param [DateTime] end_datetime ending date time for range query + def find_by_date_created(start_datetime, end_datetime = nil) + return [] if start_datetime.blank? # no date just return nothing + relation.where(build_date_query(start_datetime, end_datetime)) + end + + def find_registered_in_date_range(start_datetime, end_datetime = nil) + find_by_date_created(start_datetime, end_datetime).merge(where_registered) + end + + def find_public_in_date_range(start_datetime, end_datetime = nil) + find_by_date_created(start_datetime, end_datetime).merge(where_public) + end + + def where_public + where_access_is 'public' + end + + def where_registered + where_access_is 'registered' + end + + def build_date_query(start_datetime, end_datetime) + start_date_str = start_datetime.utc.strftime(date_format) + end_date_str = if end_datetime.blank? + "*" + else + end_datetime.utc.strftime(date_format) + end + "system_create_dtsi:[#{start_date_str} TO #{end_date_str}]" + end + + delegate :count, to: :relation + + def relation + Hyrax::WorkRelation.new + end + + private + + def where_access_is(access_level) + relation.where Hydra.config.permissions.read.group => access_level + end + + def date_format + "%Y-%m-%dT%H:%M:%SZ" + end + end + end +end diff --git a/app/services/hyrax/statistics/works/count.rb b/app/services/hyrax/statistics/works/count.rb index b07ad7b08a..7e752c4257 100644 --- a/app/services/hyrax/statistics/works/count.rb +++ b/app/services/hyrax/statistics/works/count.rb @@ -43,7 +43,7 @@ def by_permission private def query_service - @query_service ||= Hyrax::QueryService.new + @query_service ||= Hyrax::Statistics::QueryService.new end def by_date_and_permission diff --git a/app/views/hyrax/admin/admin_sets/_form_visibility.html.erb b/app/views/hyrax/admin/admin_sets/_form_visibility.html.erb index cd3d506fc8..590f407a04 100644 --- a/app/views/hyrax/admin/admin_sets/_form_visibility.html.erb +++ b/app/views/hyrax/admin/admin_sets/_form_visibility.html.erb @@ -14,10 +14,16 @@