diff --git a/.rubocop.yml b/.rubocop.yml index 60da7e7d6..e90e64b21 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -156,4 +156,5 @@ Style/EmptyCaseCondition: Layout/LineLength: Exclude: - 'spec/features/dashboard/work_version_form_spec.rb' + - 'spec/forms/work_deposit_pathways/instrument/publish_form_spec.rb' diff --git a/app/components/citation_component.rb b/app/components/citation_component.rb index f29980333..7a24f0308 100644 --- a/app/components/citation_component.rb +++ b/app/components/citation_component.rb @@ -13,7 +13,7 @@ def render? end def citation_display - return unless deposit_pathway.data_and_code? + return unless deposit_pathway.data_and_code? || deposit_pathway.instrument? "#{creators_citation_display}(#{year_published}). #{work_version.title} [Data set]. Scholarsphere.#{doi_url}" end diff --git a/app/components/delete_resource_button_component.rb b/app/components/delete_resource_button_component.rb index e49358eaf..76296bbd8 100644 --- a/app/components/delete_resource_button_component.rb +++ b/app/components/delete_resource_button_component.rb @@ -57,7 +57,9 @@ def work_version? 'WorkDepositPathway::ScholarlyWorks::PublishForm', 'WorkDepositPathway::General::DetailsForm', 'WorkDepositPathway::DataAndCode::DetailsForm', - 'WorkDepositPathway::DataAndCode::PublishForm' + 'WorkDepositPathway::DataAndCode::PublishForm', + 'WorkDepositPathway::Instrument::DetailsForm', + 'WorkDepositPathway::Instrument::PublishForm' ].include?(type) end diff --git a/app/components/thumbnail_component.rb b/app/components/thumbnail_component.rb index 5e54e85b1..35e1b815b 100644 --- a/app/components/thumbnail_component.rb +++ b/app/components/thumbnail_component.rb @@ -60,6 +60,7 @@ def icon_map dataset: 'analytics', dissertation: 'subject', image: 'image', + instrument: 'precision_manufacturing', journal: 'subject', map_or_cartographic_material: 'map', masters_culminating_experience: 'landscape', diff --git a/app/components/work_version_metadata_component.rb b/app/components/work_version_metadata_component.rb index 0f1b464b2..b8a3e595d 100644 --- a/app/components/work_version_metadata_component.rb +++ b/app/components/work_version_metadata_component.rb @@ -23,7 +23,18 @@ class WorkVersionMetadataComponent < BaseMetadataComponent :based_near, :related_url, :source, - :deposited_at + :deposited_at, + :owner, + :manufacturer, + :model, + :instrument_type, + :measured_variable, + :available_date, + :decommission_date, + :related_identifier, + :alternative_identifier, + :instrument_resource_type, + :funding_reference ].freeze MINI_ATTRIBUTES = [ diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index f599e26e3..4b76bd7b8 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -142,6 +142,17 @@ def index config.add_show_field 'language_tesim', label: 'Language' config.add_show_field 'identifier_tesim', label: 'Identifier' config.add_show_field 'based_near_tesim', label: 'Based Near' + config.add_show_field 'owner_tesim', label: 'Owner' + config.add_show_field 'manufacturer_tesim', label: 'Manufacturer' + config.add_show_field 'model_tesim', label: 'Model' + config.add_show_field 'instrument_type_tesim', label: 'Instrument Type' + config.add_show_field 'measured_variable_tesim', label: 'Measured Variable' + config.add_show_field 'available_date_tesim', label: 'Available Date' + config.add_show_field 'decommission_date_tesim', label: 'Decommission Date' + config.add_show_field 'related_identifier_tesim', label: 'Related Identifier' + config.add_show_field 'alternative_identifier_tesim', label: 'Alternative Identifier' + config.add_show_field 'instrument_resource_type_tesim', label: 'Resource Type' + config.add_show_field 'funding_reference_tesim', label: 'Funding Reference' config.add_show_field 'related_url_tesim', label: 'Related URL' config.add_show_field 'source_tesim', label: 'Source' config.add_show_field 'version_number_isi', label: 'Version Number' diff --git a/app/controllers/dashboard/form/publish_controller.rb b/app/controllers/dashboard/form/publish_controller.rb index 401347918..1caa09b9b 100644 --- a/app/controllers/dashboard/form/publish_controller.rb +++ b/app/controllers/dashboard/form/publish_controller.rb @@ -121,6 +121,17 @@ def work_version_params :published_date, :depositor_agreement, :draft_curation_requested, + :owner, + :manufacturer, + :model, + :instrument_type, + :measured_variable, + :available_date, + :decommission_date, + :related_identifier, + :alternative_identifier, + :instrument_resource_type, + :funding_reference, :mint_doi_requested, keyword: [], contributor: [], diff --git a/app/controllers/dashboard/form/work_version_details_controller.rb b/app/controllers/dashboard/form/work_version_details_controller.rb index f1bf605be..3f9427d42 100644 --- a/app/controllers/dashboard/form/work_version_details_controller.rb +++ b/app/controllers/dashboard/form/work_version_details_controller.rb @@ -64,6 +64,17 @@ def work_version_params :rights, :version_name, :published_date, + :owner, + :manufacturer, + :model, + :instrument_type, + :measured_variable, + :available_date, + :decommission_date, + :related_identifier, + :alternative_identifier, + :instrument_resource_type, + :funding_reference, keyword: [], contributor: [], publisher: [], diff --git a/app/controllers/dashboard/work_versions_controller.rb b/app/controllers/dashboard/work_versions_controller.rb index 88a75eb41..959fc67d7 100644 --- a/app/controllers/dashboard/work_versions_controller.rb +++ b/app/controllers/dashboard/work_versions_controller.rb @@ -139,6 +139,17 @@ def metadata_params :rights, :version_name, :published_date, + :owner, + :manufacturer, + :model, + :instrument_type, + :measured_variable, + :available_date, + :decommission_date, + :related_identifier, + :alternative_identifier, + :instrument_resource_type, + :funding_reference, keyword: [], contributor: [], publisher: [], diff --git a/app/forms/work_deposit_pathway.rb b/app/forms/work_deposit_pathway.rb index 2fda402a0..828e248c1 100644 --- a/app/forms/work_deposit_pathway.rb +++ b/app/forms/work_deposit_pathway.rb @@ -10,6 +10,8 @@ def details_form ScholarlyWorks::DetailsForm.new(resource) elsif data_and_code? DataAndCode::DetailsForm.new(resource) + elsif instrument? + Instrument::DetailsForm.new(resource) else General::DetailsForm.new(resource) end @@ -20,6 +22,8 @@ def publish_form ScholarlyWorks::PublishForm.new(resource) elsif data_and_code? DataAndCode::PublishForm.new(resource) + elsif instrument? + Instrument::PublishForm.new(resource) else resource end @@ -34,7 +38,7 @@ def allows_curation_request? end def allows_mint_doi_request? - data_and_code? && @resource.doi_blank? && DoiMintingStatus.new(@resource.work).blank? + (data_and_code? || instrument?) && @resource.doi_blank? && DoiMintingStatus.new(@resource.work).blank? end def work? @@ -45,6 +49,10 @@ def data_and_code? Work::Types.data_and_code.include?(work_type) end + def instrument? + Work::Types.instrument.include?(work_type) + end + private attr_reader :resource @@ -282,4 +290,113 @@ def includes_readme_file end end end + + module Instrument + class DetailsForm < DetailsFormBase + def self.form_fields + WorkVersionFormBase::COMMON_FIELDS.union( + %w{ + title + owner + identifier + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference + } + ).freeze + end + + form_fields.each do |attr_name| + delegate attr_name, to: :work_version, prefix: false + delegate "#{attr_name}=", to: :work_version, prefix: false + end + + def form_partial + 'instrument_work_version' + end + end + + class PublishForm < WorkVersionFormBase + def self.form_fields + WorkVersionFormBase::COMMON_FIELDS.union( + %w{ + title + owner + identifier + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference + rights + depositor_agreement + contributor + } + ).freeze + end + + form_fields.each do |attr_name| + delegate attr_name, to: :work_version, prefix: false + delegate "#{attr_name}=", to: :work_version, prefix: false + end + + validate :includes_readme_file_and_image, + if: :published? + + validates :decommission_date, + edtf_date: true + + validates :available_date, + edtf_date: true + + def form_partial + 'instrument_work_version' + end + + delegate :aasm_state=, + :aasm_state, + :publish, + :file_resources, + :work_attributes=, + :creators_attributes=, + :creators, + :contributor, + :file_version_memberships, + :initial_draft?, + :aasm, + :update_column, + :draft_curation_requested=, + :mint_doi_requested=, + :set_thumbnail_selection, + :set_publisher_as_scholarsphere, + to: :work_version, + prefix: false + + private + + def includes_readme_file_and_image + unless file_resources.find do |fr| + fr.file_data['metadata']['size'].positive? && + fr.file_data['metadata']['filename'] =~ /readme/i + end && file_resources.find do |fr| + (fr.file_data['metadata']['filename'] !~ /readme/i && + fr.file_data['metadata']['filename'] =~ /png|jpeg|tiff/i) + end + errors.add(:file_resources, :readme_and_image) + end + end + end + end end diff --git a/app/javascript/controllers/work_type_controller.js b/app/javascript/controllers/work_type_controller.js new file mode 100644 index 000000000..4360c5aa4 --- /dev/null +++ b/app/javascript/controllers/work_type_controller.js @@ -0,0 +1,18 @@ +import { Controller } from 'stimulus' + +export default class extends Controller { + static targets = ['workTypeSelect', 'helpText'] + + connect () { + this.toggleHelpText() + this.workTypeSelectTarget.addEventListener('change', () => this.toggleHelpText()) + } + + toggleHelpText () { + if (this.workTypeSelectTarget.value === 'instrument') { + this.helpTextTarget.style.display = 'block' + } else { + this.helpTextTarget.style.display = 'none' + } + } +} diff --git a/app/models/work.rb b/app/models/work.rb index 6d7882710..de32c34b2 100644 --- a/app/models/work.rb +++ b/app/models/work.rb @@ -61,7 +61,7 @@ class Work < ApplicationRecord module Types def self.all - general.union(scholarly_works).union(data_and_code).freeze + general.union(scholarly_works).union(data_and_code).union(instrument).freeze end def self.general @@ -102,6 +102,12 @@ def self.data_and_code ].freeze end + def self.instrument + %w[ + instrument + ].freeze + end + def self.default 'dataset' end diff --git a/app/models/work_version.rb b/app/models/work_version.rb index 3b899f391..4f8be2889 100644 --- a/app/models/work_version.rb +++ b/app/models/work_version.rb @@ -31,7 +31,18 @@ class WorkVersion < ApplicationRecord identifier: [:string, array: true, default: []], based_near: [:string, array: true, default: []], related_url: [:string, array: true, default: []], - source: [:string, array: true, default: []] + source: [:string, array: true, default: []], + owner: :string, + manufacturer: :string, + model: :string, + instrument_type: :string, + measured_variable: :string, + available_date: :string, + decommission_date: :string, + related_identifier: :string, + alternative_identifier: :string, + instrument_resource_type: :string, + funding_reference: :string belongs_to :work, inverse_of: :versions @@ -160,6 +171,14 @@ def label(id) edtf_date: true, if: :published? + validates :decommission_date, + edtf_date: true, + if: :published? + + validates :available_date, + edtf_date: true, + if: :published? + validates :description, presence: true, if: :published? @@ -188,6 +207,7 @@ def label(id) to: :published, after: Proc.new { work.try(:update_deposit_agreement) + set_publisher_as_scholarsphere if work_type == 'instrument' self.reload_on_index = true } end @@ -227,6 +247,17 @@ def label(id) rights subtitle version_name + owner + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference ].each do |field| define_method "#{field}=" do |val| super(val.presence) @@ -299,6 +330,10 @@ def set_thumbnail_selection end end + def set_publisher_as_scholarsphere + metadata['publisher'] = ['Scholarsphere'] + end + def initial_draft? version_number == 1 && (draft? || temporarily_published_draft?) diff --git a/app/reports/all_work_versions_report.rb b/app/reports/all_work_versions_report.rb index ae60d05d8..d72ddceb8 100644 --- a/app/reports/all_work_versions_report.rb +++ b/app/reports/all_work_versions_report.rb @@ -28,6 +28,17 @@ def headers based_near related_url source + owner + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference views ] end @@ -64,6 +75,17 @@ def rows wv.based_near, wv.related_url, wv.source, + wv.owner, + wv.manufacturer, + wv.model, + wv.instrument_type, + wv.measured_variable, + wv.available_date, + wv.decommission_date, + wv.related_identifier, + wv.alternative_identifier, + wv.instrument_resource_type, + wv.funding_reference, views ] diff --git a/app/services/edtf_date.rb b/app/services/edtf_date.rb index 31f8271b6..ca221ab2c 100644 --- a/app/services/edtf_date.rb +++ b/app/services/edtf_date.rb @@ -2,7 +2,7 @@ module EdtfDate def self.valid?(str) - Date.edtf(str).present? + Date.edtf(str).present? || str.blank? end def self.humanize(str) diff --git a/app/views/dashboard/form/details/_instrument_work_version_fields.html.erb b/app/views/dashboard/form/details/_instrument_work_version_fields.html.erb new file mode 100644 index 000000000..a264ac846 --- /dev/null +++ b/app/views/dashboard/form/details/_instrument_work_version_fields.html.erb @@ -0,0 +1,16 @@ +<%= render 'dashboard/form/details/common_work_version_required_fields', form: form %> + +
+ <%= render 'form_fields/multi_text', form: form, attribute: :keyword %> + <%= render 'form_fields/text', form: form, attribute: :owner %> + <%= render 'form_fields/text', form: form, attribute: :manufacturer %> + <%= render 'form_fields/text', form: form, attribute: :model %> + <%= render 'form_fields/text', form: form, attribute: :instrument_type %> + <%= render 'form_fields/text', form: form, attribute: :measured_variable %> + <%= render 'form_fields/text', form: form, attribute: :available_date %> + <%= render 'form_fields/text', form: form, attribute: :decommission_date %> + <%= render 'form_fields/text', form: form, attribute: :related_identifier %> + <%= render 'form_fields/text', form: form, attribute: :alternative_identifier %> + <%= render 'form_fields/text', form: form, attribute: :instrument_resource_type %> + <%= render 'form_fields/text', form: form, attribute: :funding_reference %> +
diff --git a/app/views/dashboard/form/files/_fields.html.erb b/app/views/dashboard/form/files/_fields.html.erb index 506ea7504..bf25c8d30 100644 --- a/app/views/dashboard/form/files/_fields.html.erb +++ b/app/views/dashboard/form/files/_fields.html.erb @@ -13,6 +13,15 @@
  • <%= t('dashboard.form.details.readme.zip') %>
  • +<% elsif deposit_pathway.instrument? %> +

    + <%= t('dashboard.form.details.readme.header') %> +

    +

    <% end %> <% if form.object.file_version_memberships.any? %> diff --git a/app/views/dashboard/form/type/_work_version_fields.html.erb b/app/views/dashboard/form/type/_work_version_fields.html.erb index 3ce6f2e58..791d52ef9 100644 --- a/app/views/dashboard/form/type/_work_version_fields.html.erb +++ b/app/views/dashboard/form/type/_work_version_fields.html.erb @@ -4,10 +4,20 @@ -
    +
    <%= render 'form_fields/text', form: form, attribute: :title, required: true %> <%= form.fields_for :work do |work_form| %> - <%= render 'form_fields/select', form: work_form, attribute: :work_type, options_for_select: Work::Types.options_for_select_box, disabled: local_assigns[:work_type_disabled] %> + <%= work_form.select :work_type, + Work::Types.options_for_select_box, + {}, + { class: 'form-control custom-select', + id: 'work_version_work_attributes_work_type', + data: { target: 'work-type.workTypeSelect' }, + disabled: local_assigns[:work_type_disabled] } %> <% end %> + +
    diff --git a/config/locales/en.yml b/config/locales/en.yml index 8e3a3ffab..be2c5e3b6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -79,6 +79,17 @@ en: visibility: Access visibility_badge: Access deposited_at: Deposited + owner: Owner + manufacturer: Manufacturer + model: Model + instrument_type: Instrument Type + measured_variable: Measured Variable + available_date: Available Date + decommission_date: Decommission Date + related_identifier: Related Identifier + alternative_identifier: Alternative Identifier + instrument_resource_type: Instrument Resource Type + funding_reference: Funding Reference user: admin_enabled: Administrative privileges enabled opt_in_stats_email: Receive monthly report on downloads and views @@ -137,6 +148,7 @@ en: blank: *required_to_publish file_resources: readme: must include a separate README file labeled as “README” in addition to other files + readme_and_image: must include a PNG, JPEG, or TIFF as well as a separate README file labeled as “README” admin: application_setting: heading: Application Settings @@ -437,11 +449,15 @@ en: required_metadata: Required Metadata required_to_publish_metadata: Needed to Publish additional_metadata: Optional Metadata + instrument_title: Use the instrument name as the work title readme: header: 'Please note:' format: Every work must include a README file labeled as “README” (e.g., README.txt, readme.md, etc.). This README file should contain essential information about your uploaded files, such as a brief description, instructions, or any other pertinent details. If you need assistance or guidance, please refer to the zip: If you are uploading a compressed file (e.g., .zip, .tar), ensure that the README file is a separate file outside the zipped files. documentation: ' ScholarSphere README template' + image: + format: Every work must include an image as either a PNG, JPEG, or TIFF file type. + zip: If you are uploading a compressed file (e.g., .zip, .tar), ensure that the README and image files are separate files outside the zipped files. contributors: edit: diff --git a/lib/data_cite/metadata/work_version.rb b/lib/data_cite/metadata/work_version.rb index 078b190eb..620f67953 100644 --- a/lib/data_cite/metadata/work_version.rb +++ b/lib/data_cite/metadata/work_version.rb @@ -12,6 +12,7 @@ class WorkVersion < Base 'dataset' => 'Dataset', 'dissertation' => 'Text', 'image' => 'Image', + 'instrument' => 'Instrument', 'journal' => 'Text', 'map_or_cartographic_material' => 'Image', 'masters_culminating_experience' => 'Text', diff --git a/openapi.yml b/openapi.yml index e6df9a54e..9ea25dcfb 100644 --- a/openapi.yml +++ b/openapi.yml @@ -269,6 +269,7 @@ components: - dataset - dissertation - image + - instrument - journal - map_or_cartographic_material - masters_culminating_experience @@ -334,6 +335,29 @@ components: type: "array" items: type: "string" + + owner: + type: "string" + manufacturer: + type: "string" + model: + type: "string" + instrument_type: + type: "string" + measured_variable: + type: "string" + available_date: + type: "string" + decommission_date: + type: "string" + related_identifier: + type: "string" + alternative_identifier: + type: "string" + instrument_resource_type: + type: "string" + funding_reference: + type: "string" related_url: type: "array" items: diff --git a/solr/conf/solrconfig.xml b/solr/conf/solrconfig.xml index 0ce87a771..34fb8009c 100644 --- a/solr/conf/solrconfig.xml +++ b/solr/conf/solrconfig.xml @@ -58,6 +58,17 @@ subject_tesim subtitle_tesim title_tesim + owner_tesim + manufacturer_tesim + model_tesim + instrument_type_tesim + measured_variable_tesim + available_date_tesim + decommission_date_tesim + related_identifier_tesim + alternative_identifier_tesim + instrument_resource_type_tesim + funding_reference_tesim work_type_ss diff --git a/spec/components/citation_component_spec.rb b/spec/components/citation_component_spec.rb index 50b3a1902..6f64bd7f7 100644 --- a/spec/components/citation_component_spec.rb +++ b/spec/components/citation_component_spec.rb @@ -4,11 +4,12 @@ RSpec.describe CitationComponent, type: :component do let(:component) { described_class.new(work_version, pathway) } - let(:pathway) { instance_double(WorkDepositPathway, data_and_code?: data_and_code) } + let(:pathway) { instance_double(WorkDepositPathway, data_and_code?: data_and_code, instrument?: instrument) } let(:data_and_code) { true } + let(:instrument) { false } describe 'rendering' do - context 'when not given a data and code pathway' do + context 'when not given a data and code or instrument pathway' do let(:data_and_code) { false } let(:work_version) { build :work_version, :published, work: build(:work, work_type: 'article') } let(:citation_component) { render_inline(component) } @@ -56,5 +57,46 @@ end end end + + context 'when given an instrument pathway' do + let(:work_version) { + build( + :work_version, + :published, + work: build(:work, work_type: 'instrument', doi: '10.26207/123'), + title: 'Citation Title', + published_date: '2024-02-16', + doi: '10.26207/123' + ) + } + let(:authorship1) { build :authorship, given_name: 'Alan', surname: 'Grant' } + let(:citation_component) { render_inline(component) } + let(:data_and_code) { false } + let(:instrument) { true } + + before { work_version.creators = [authorship1] } + + context 'when there is one creator' do + let(:expected_citation) { 'Grant, Alan (2024). Citation Title [Data set]. Scholarsphere. https://doi.org/10.26207/123' } + + it 'renders the citation' do + expect(citation_component.css('div.keyline')).not_to be_empty + expect(citation_component.text).to include(expected_citation) + end + end + + context 'when there are multiple creators' do + let(:expected_citation) { 'Grant, Alan; Sattler, Ellie; Malcolm, Ian (2024). Citation Title [Data set]. Scholarsphere. https://doi.org/10.26207/123' } + let(:authorship2) { build :authorship, given_name: 'Ellie', surname: 'Sattler' } + let(:authorship3) { build :authorship, given_name: 'Ian', surname: 'Malcolm' } + + before { work_version.creators << [authorship2, authorship3] } + + it 'renders the instrument citation' do + expect(citation_component.css('div.keyline')).not_to be_empty + expect(citation_component.text).to include(expected_citation) + end + end + end end end diff --git a/spec/factories/work_versions.rb b/spec/factories/work_versions.rb index d9cf2b9a2..9c072d5c6 100644 --- a/spec/factories/work_versions.rb +++ b/spec/factories/work_versions.rb @@ -30,6 +30,10 @@ association :work, :article end + trait :instrument do + association :work, :instrument + end + trait :initial_draft do after(:build, :stub) do |work_version, evaluator| evaluator.work.versions.destroy_all @@ -78,6 +82,17 @@ published_date { Faker::Date.between(from: 2.years.ago, to: Date.today).iso8601 } end + # A draft instrument that has everything needed to pass validations and be published + trait :instrument_able_to_be_published do + instrument + draft + with_files + with_readme_file + with_creators + description { Faker::Lorem.paragraph } + published_date { Faker::Date.between(from: 2.years.ago, to: Date.today).iso8601 } + end + # A valid published work-version trait :published do able_to_be_published @@ -107,6 +122,8 @@ based_near { FactoryBotHelpers.fancy_geo_location } related_url { Faker::Internet.url } source { Faker::SlackEmoji.emoji } + owner { Faker::Book.author } + model { Faker::Number.leading_zero_number(digits: 5) } end end end diff --git a/spec/factories/works.rb b/spec/factories/works.rb index 75efbfc43..525bcbe4b 100644 --- a/spec/factories/works.rb +++ b/spec/factories/works.rb @@ -82,6 +82,10 @@ work_type { 'article' } end + trait(:instrument) do + work_type { 'instrument' } + end + trait(:general) do work_type { 'audio' } end diff --git a/spec/features/dashboard/work_version_form_spec.rb b/spec/features/dashboard/work_version_form_spec.rb index 2f90332f9..b4feaa9cd 100644 --- a/spec/features/dashboard/work_version_form_spec.rb +++ b/spec/features/dashboard/work_version_form_spec.rb @@ -359,6 +359,120 @@ end end end + + context 'when selecting a work type that uses the instrument deposit pathway' do + it 'shows only the fields for instrument works' do + visit dashboard_form_work_versions_path + + FeatureHelpers::DashboardForm.fill_in_minimal_work_details_for_instrument_draft(metadata) + FeatureHelpers::DashboardForm.save_and_continue + + expect(page).not_to have_field('publisher_statement') + expect(page).not_to have_field('work_version_based_near') + expect(page).not_to have_field('work_version_source') + expect(page).not_to have_field('work_version_version_name') + expect(page).to have_field('work_version_owner') + expect(page).to have_field('work_version_model') + end + + context 'when saving as draft and exiting' do + it 'creates a new work with all fields provided' do + initial_work_count = Work.count + + visit dashboard_form_work_versions_path + + FeatureHelpers::DashboardForm.fill_in_minimal_work_details_for_instrument_draft(metadata) + FeatureHelpers::DashboardForm.save_as_draft_and_exit + + expect(Work.count).to eq(initial_work_count + 1) + + new_work = Work.last + expect(new_work.work_type).to eq 'instrument' + expect(new_work.versions.length).to eq 1 + + new_work_version = new_work.versions.last + expect(page).to have_content(metadata[:title]) + expect(new_work_version.title).to eq metadata[:title] + expect(new_work_version.version_number).to eq 1 + + expect(page).to have_current_path(resource_path(new_work_version.uuid)) + expect(SolrIndexingJob).to have_received(:perform_later).at_least(:once) + end + end + + context 'when saving and_continuing' do + it 'creates a new work with all fields provided' do + initial_work_count = Work.count + + visit dashboard_form_work_versions_path + + FeatureHelpers::DashboardForm.fill_in_minimal_work_details_for_instrument_draft(metadata) + FeatureHelpers::DashboardForm.save_and_continue + FeatureHelpers::DashboardForm.fill_in_instrument_work_details(metadata) + FeatureHelpers::DashboardForm.save_and_continue + + expect(Work.count).to eq(initial_work_count + 1) + new_work = Work.last + expect(new_work.work_type).to eq 'instrument' + expect(new_work.versions.length).to eq 1 + + new_work_version = new_work.versions.last + + expect(new_work_version.version_number).to eq 1 + expect(new_work_version.title).to eq metadata[:title] + expect(new_work_version.owner).to eq metadata[:owner] + expect(new_work_version.model).to eq metadata[:model] + + expect(page).to have_current_path(dashboard_form_contributors_path('work_version', new_work_version)) + expect(SolrIndexingJob).to have_received(:perform_later).at_least(:twice) + end + + context 'with invalid data' do + it 'does not save the data and rerenders the form with errors' do + visit dashboard_form_work_versions_path + + FeatureHelpers::DashboardForm.fill_in_minimal_work_details_for_instrument_draft(metadata) + FeatureHelpers::DashboardForm.save_and_continue + FeatureHelpers::DashboardForm.fill_in_instrument_work_details(metadata) + fill_in 'work_version_description', with: '' + FeatureHelpers::DashboardForm.save_and_continue + + new_work_version = Work.last.versions.last + + expect(page).to have_current_path(dashboard_form_work_version_details_path(new_work_version)) + expect(page).to have_content 'Description is required to publish the work' + expect(SolrIndexingJob).to have_received(:perform_later).once + + expect(new_work_version.description).to be_nil + expect(new_work_version.published_date).to be_nil + expect(new_work_version.subtitle).to be_nil + expect(new_work_version.version_name).to be_nil + expect(new_work_version.publisher).to be_empty + expect(new_work_version.subject).to be_empty + expect(new_work_version.language).to be_empty + expect(new_work_version.related_url).to be_empty + expect(new_work_version.identifier).to be_empty + expect(new_work_version.based_near).to be_empty + expect(new_work_version.source).to be_empty + end + end + end + + context 'when saving-and-continuing, then hitting cancel' do + it 'returns to the resource page' do + visit dashboard_form_work_versions_path + + FeatureHelpers::DashboardForm.fill_in_minimal_work_details_for_instrument_draft(metadata) + FeatureHelpers::DashboardForm.save_and_continue + FeatureHelpers::DashboardForm.fill_in_instrument_work_details(metadata) + FeatureHelpers::DashboardForm.save_and_continue + + FeatureHelpers::DashboardForm.cancel + + expect(page).to have_content metadata[:title] + end + end + end end describe 'The Work Details tab for an existing draft work' do @@ -876,6 +990,32 @@ expect(page).not_to have_field('work_version_work_attributes_visibility_authenticated') end end + + context 'with a work that uses the instrument works deposit pathway' do + let(:work) { create :work, :instrument, versions_count: 1 } + let(:work_version) { work.versions.first } + let(:user) { work.depositor.user } + + it 'shows only the fields for an instrument work' do + visit dashboard_form_publish_path(work_version) + + expect(page).not_to have_field('work_version_based_near') + expect(page).not_to have_field('work_version_source') + expect(page).not_to have_field('work_version_version_name') + expect(page).not_to have_field('work_version_publisher_statement') + expect(page).to have_field('work_version_keyword') + expect(page).to have_field('work_version_owner') + expect(page).to have_field('work_version_manufacturer') + expect(page).to have_field('work_version_instrument_type') + expect(page).to have_field('work_version_measured_variable') + expect(page).to have_field('work_version_available_date') + expect(page).to have_field('work_version_decommission_date') + expect(page).to have_field('work_version_related_identifier') + expect(page).to have_field('work_version_alternative_identifier') + expect(page).to have_field('work_version_instrument_resource_type') + expect(page).to have_field('work_version_funding_reference') + end + end end describe 'Publishing a new work from end-to-end', js: true do @@ -1246,7 +1386,18 @@ def mock_solr_indexing_job describe 'minting a doi', js: true do let(:user) { work_version.work.depositor.user } - context 'with a draft eligible for doi minting' do + context 'with an instrument draft eligible for doi minting' do + let(:work) { create :work, work_type: 'instrument', versions_count: 1, has_draft: true, doi: nil } + let(:work_version) { work.versions.first } + + it 'renders a checkbox requesting a doi be minted upon publish' do + visit dashboard_form_publish_path(work_version) + + expect(page).to have_content(I18n.t('dashboard.form.publish.doi.label')) + end + end + + context 'with a data and code draft eligible for doi minting' do let(:work) { create :work, work_type: 'dataset', versions_count: 1, has_draft: true, doi: nil } let(:work_version) { work.versions.first } diff --git a/spec/forms/work_deposit_pathway_spec.rb b/spec/forms/work_deposit_pathway_spec.rb index e530539fc..6521da90d 100644 --- a/spec/forms/work_deposit_pathway_spec.rb +++ b/spec/forms/work_deposit_pathway_spec.rb @@ -314,6 +314,44 @@ end end + context 'when the given work version has an instrument type' do + %w[ + instrument + ].each do |t| + let(:type) { t } + + context 'when the associated work does not have a doi' do + let(:doi_blank) { true } + + context 'when doi minting is not already in progress' do + before do + allow_any_instance_of(DoiMintingStatus).to receive(:blank?).and_return(true) + end + + it 'returns true' do + expect(pathway.allows_mint_doi_request?).to eq true + end + end + + context 'when doi minting is already in progress' do + before do + allow_any_instance_of(DoiMintingStatus).to receive(:blank?).and_return(false) + end + + it 'returns false' do + expect(pathway.allows_mint_doi_request?).to eq false + end + end + end + + context 'when the associated work has a doi' do + it 'returns false' do + expect(pathway.allows_mint_doi_request?).to eq false + end + end + end + end + context 'when the given work version does not have a data and code type' do %w[ article diff --git a/spec/forms/work_deposit_pathways/instrument/details_form_spec.rb b/spec/forms/work_deposit_pathways/instrument/details_form_spec.rb new file mode 100644 index 000000000..e6f06281e --- /dev/null +++ b/spec/forms/work_deposit_pathways/instrument/details_form_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'rails_helper' +require_relative '../_shared_examples_for_work_deposit_pathway_form' +require_relative '../_shared_examples_for_details_form' + +RSpec.describe WorkDepositPathway::Instrument::DetailsForm, type: :model do + subject(:form) { described_class.new(wv) } + + let(:wv) { + build( + :work_version, + attributes: { + 'description' => description, + 'published_date' => '2021', + 'owner' => 'test owner', + 'manufacturer' => 'test manufacturer', + 'model' => 'test model', + 'instrument_type' => 'test type', + 'measured_variable' => 'test measured variable', + 'available_date' => '2022', + 'decommission_date' => '2024', + 'related_identifier' => 'test related id', + 'alternative_identifier' => 'test alternative id', + 'instrument_resource_type' => 'test resource type', + 'funding_reference' => 'test funding ref' + } + ) + } + + let(:description) { 'test description' } + + it_behaves_like 'a work deposit pathway form' + it_behaves_like 'a work deposit pathway details form' + + describe '.form_fields' do + it "returns a frozen array of the names of the form's fields" do + expect(described_class.form_fields).to match_array %w{ + title + owner + identifier + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference + description + keyword + language + published_date + publisher + related_url + subject + subtitle + } + + expect(described_class.form_fields).to be_frozen + end + end + + describe '#form_partial' do + it 'returns instrument_work_version' do + expect(form.form_partial).to eq 'instrument_work_version' + end + end + + describe 'attribute initialization' do + it "sets the form attributes correctly from the given object's attributes" do + expect(form).to have_attributes( + { + description: 'test description', + published_date: '2021', + owner: 'test owner', + manufacturer: 'test manufacturer', + model: 'test model', + instrument_type: 'test type', + measured_variable: 'test measured variable', + available_date: '2022', + decommission_date: '2024', + related_identifier: 'test related id', + alternative_identifier: 'test alternative id', + instrument_resource_type: 'test resource type', + funding_reference: 'test funding ref' + } + ) + end + end +end diff --git a/spec/forms/work_deposit_pathways/instrument/publish_form_spec.rb b/spec/forms/work_deposit_pathways/instrument/publish_form_spec.rb new file mode 100644 index 000000000..8f1faa4ea --- /dev/null +++ b/spec/forms/work_deposit_pathways/instrument/publish_form_spec.rb @@ -0,0 +1,639 @@ +# frozen_string_literal: true + +require 'rails_helper' +require_relative '../_shared_examples_for_work_deposit_pathway_form' + +RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = nil +RSpec.describe WorkDepositPathway::Instrument::PublishForm, type: :model do + subject(:form) { described_class.new(wv) } + + let(:wv) { + build( + :work_version, + attributes: { + 'title' => 'test title', + 'description' => description, + 'published_date' => '2021', + 'owner' => 'test owner', + 'manufacturer' => 'test manufacturer', + 'model' => 'test model', + 'instrument_type' => 'test type', + 'measured_variable' => 'test measured variable', + 'available_date' => '2022', + 'decommission_date' => '2024', + 'related_identifier' => 'test related id', + 'alternative_identifier' => 'test alternative id', + 'instrument_resource_type' => 'test resource type', + 'funding_reference' => 'test funding ref' + } + ) + } + + let(:description) { 'test description' } + + it_behaves_like 'a work deposit pathway form' + + it { is_expected.to delegate_method(:aasm_state).to(:work_version) } + it { is_expected.to delegate_method(:publish).to(:work_version) } + it { is_expected.to delegate_method(:file_resources).to(:work_version) } + it { is_expected.to delegate_method(:creators).to(:work_version) } + it { is_expected.to delegate_method(:contributor).to(:work_version) } + it { is_expected.to delegate_method(:file_version_memberships).to(:work_version) } + it { is_expected.to delegate_method(:initial_draft?).to(:work_version) } + it { is_expected.to delegate_method(:aasm).to(:work_version) } + it { is_expected.to delegate_method(:update_column).to(:work_version) } + it { is_expected.to delegate_method(:set_thumbnail_selection).to(:work_version) } + + describe '#aasm_state=' do + before { allow(wv).to receive(:aasm_state=) } + + let(:arg) { double } + + it 'delegates to the given work version' do + form.aasm_state = arg + expect(wv).to have_received(:aasm_state=).with(arg) + end + end + + describe '#work_attributes=' do + before { allow(wv).to receive(:work_attributes=) } + + let(:arg) { double } + + it 'delegates to the given work version' do + form.work_attributes = arg + expect(wv).to have_received(:work_attributes=).with(arg) + end + end + + describe '#creators_attributes=' do + before { allow(wv).to receive(:creators_attributes=) } + + let(:arg) { double } + + it 'delegates to the given work version' do + form.creators_attributes = arg + expect(wv).to have_received(:creators_attributes=).with(arg) + end + end + + describe '.form_fields' do + it "returns a frozen array of the names of the form's fields" do + expect(described_class.form_fields).to match_array %w{ + title + owner + identifier + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference + description + keyword + language + published_date + publisher + related_url + subject + subtitle + contributor + depositor_agreement + rights + } + + expect(described_class.form_fields).to be_frozen + end + end + + describe 'attribute initialization' do + it "sets the form attributes correctly from the given object's attributes" do + expect(form).to have_attributes( + { + title: 'test title', + description: 'test description', + published_date: '2021', + owner: 'test owner', + manufacturer: 'test manufacturer', + model: 'test model', + instrument_type: 'test type', + measured_variable: 'test measured variable', + available_date: '2022', + decommission_date: '2024', + related_identifier: 'test related id', + alternative_identifier: 'test alternative id', + instrument_resource_type: 'test resource type', + funding_reference: 'test funding ref' + } + ) + end + end + + describe 'validation' do + context "when the form's work version is otherwise valid for publishing" do + let(:wv) { build :work_version, :with_creators, description: 'description', published_date: '2020' } + + context "when the form's work version is published" do + before { wv.publish } + + context "when the form's work version has an image file that does not match 'readme'" do + before { wv.file_resources << build(:file_resource) } + + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + end + + context "when the form's work version does not have an image file" do + before { wv.file_resources << build(:file_resource, :pdf) } + + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + end + end + end + end + end + + context "when the form's work version is not published" do + context "when the form's work version has an image file with a name that does not match 'readme'" do + before { wv.file_resources << build(:file_resource) } + + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is valid' do + expect(form).to be_valid + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + end + + context "when the form's work version does not have an image file" do + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is valid' do + expect(form).to be_valid + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + end + end + end + + context "when the form's work version is not otherwise valid for publishing" do + let(:wv) { build :work_version, :with_creators, description: nil, published_date: '2020' } + + context "when the form's work version is published" do + before { wv.publish } + + context "when the form's work version has an image file with a name that does not match 'readme'" do + before { wv.file_resources << build(:file_resource) } + + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + end + end + + context "when the form's work version does not have an image file" do + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is invalid' do + expect(form).not_to be_valid + expect(form.errors[:file_resources]).to include(I18n.t('activemodel.errors.models.work_version.attributes.file_resources.readme_and_image')) + expect(form.errors[:description]).to include(I18n.t('activerecord.errors.models.work_version.attributes.description.blank')) + end + end + end + end + end + + context "when the form's work version is not published" do + context "when the form's work version has aan image file with a name that does not match 'readme'" do + before { wv.file_resources << build(:file_resource) } + + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is valid' do + expect(form).to be_valid + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + end + + context "when the form's work version does not have an image file" do + context "when the form's work version does not have a file with a name that matches 'readme'" do + it 'is valid' do + expect(form).to be_valid + end + end + + context "when the form's work version has a file named 'README.md" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_md) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + + context "when the form's work version has a file named 'readme.txt" do + context 'when the file is empty' do + before { wv.file_resources << build(:file_resource, :empty_readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + + context 'when the file is not empty' do + before { wv.file_resources << build(:file_resource, :readme_txt) } + + it 'is valid' do + expect(form).to be_valid + end + end + end + end + end + end + end + + describe '#form_partial' do + it 'returns instrument_work_version' do + expect(form.form_partial).to eq 'instrument_work_version' + end + end + + describe '#save' do + let(:context) { double } + + before do + allow(wv).to receive(:save).with(context: context).and_return true + allow(wv).to receive(:attributes=) + end + + context "when the form's work version is valid" do + context 'when the form is valid' do + it "saves the form's work version" do + form.save(context: context) + expect(wv).to have_received(:save).with(context: context) + end + + context 'when the work version saves successfully' do + it 'returns true' do + expect(form.save(context: context)).to eq true + end + end + end + + context 'when the form is not valid' do + before { wv.publish } + + it 'returns false' do + expect(form.save(context: context)).to eq false + end + + it 'does not persist the form data' do + form.save(context: context) + expect(wv).not_to have_received(:save) + end + + it 'sets errors on the form' do + form.save(context: context) + expect(form.errors[:file_resources]).not_to be_empty + end + end + end + + context "when the form's work version is invalid" do + before do + wv.errors.add(:description, 'bad data!') + allow(wv).to receive(:valid?).and_return false + end + + context 'when the form is valid' do + it "transfers the work version's errors to the form" do + form.save(context: context) + expect(form.errors[:description]).to include 'bad data!' + end + + it 'does not persist the form data' do + form.save(context: context) + expect(wv).not_to have_received(:save) + end + + it 'returns false' do + expect(form.save(context: context)).to eq false + end + end + + context 'when the form is not valid' do + before { wv.publish } + + it 'sets errors on the form' do + form.save(context: context) + expect(form.errors[:description]).not_to be_empty + end + + it "transfers the work version's errors to the form" do + form.save(context: context) + expect(form.errors[:description]).to include 'bad data!' + end + + it 'does not persist the form data' do + form.save(context: context) + expect(wv).not_to have_received(:save) + end + + it 'returns false' do + expect(form.save(context: context)).to eq false + end + end + end + end +end diff --git a/spec/models/work_spec.rb b/spec/models/work_spec.rb index 7728cbf33..919605845 100644 --- a/spec/models/work_spec.rb +++ b/spec/models/work_spec.rb @@ -123,6 +123,7 @@ 'dataset', 'dissertation', 'image', + 'instrument', 'journal', 'map_or_cartographic_material', 'masters_culminating_experience', @@ -280,6 +281,7 @@ dataset: 'dataset', dissertation: 'dissertation', image: 'image', + instrument: 'instrument', journal: 'journal', map_or_cartographic_material: 'map_or_cartographic_material', masters_culminating_experience: 'masters_culminating_experience', @@ -540,6 +542,17 @@ removed_at_dtsi withdrawn_at_dtsi imported_metadata_from_rmd_tesim + alternative_identifier_tesim + instrument_type_tesim + available_date_tesim + decommission_date_tesim + funding_reference_tesim + instrument_resource_type_tesim + manufacturer_tesim + measured_variable_tesim + model_tesim + owner_tesim + related_identifier_tesim ) end diff --git a/spec/models/work_version_spec.rb b/spec/models/work_version_spec.rb index e1ab939a7..47c7aba72 100644 --- a/spec/models/work_version_spec.rb +++ b/spec/models/work_version_spec.rb @@ -85,6 +85,10 @@ end describe 'states' do + subject(:work_version) { build(:work_version, work: work) } + + let(:work) { build(:work) } + it { is_expected.to have_state(:draft) } it { is_expected.to transition_from(:draft).to(:published).on_event(:publish) } it { is_expected.to transition_from(:published).to(:withdrawn).on_event(:withdraw) } @@ -498,6 +502,30 @@ expect(work_version).to be_published expect(work_version.reload.published_at).to be_present.and be_within(1.second).of(Time.zone.now) end + + context 'with a work that uses the instrument works deposit pathway' do + let(:work_version) { create :work_version, :instrument_able_to_be_published, work: build(:work, work_type: 'instrument') } + + it 'sets the publisher to Scholarsphere automatically' do + work_version.save + expect(work_version.publisher).to eq [] + work_version.publish! + expect(work_version).to be_published + expect(work_version.reload.publisher).to eq ['Scholarsphere'] + end + end + + context 'with a work that does not use the instrument works deposit pathway' do + let(:work_version) { create :work_version, :able_to_be_published, work: build(:work, work_type: 'article') } + + it 'does not edit the publisher field' do + work_version.save + expect(work_version.publisher).to eq [] + work_version.publish! + expect(work_version).to be_published + expect(work_version.reload.publisher).to eq [] + end + end end describe '#force_destroy' do diff --git a/spec/reports/all_work_versions_report_spec.rb b/spec/reports/all_work_versions_report_spec.rb index a6c647449..42e89ffe1 100644 --- a/spec/reports/all_work_versions_report_spec.rb +++ b/spec/reports/all_work_versions_report_spec.rb @@ -32,6 +32,17 @@ based_near related_url source + owner + manufacturer + model + instrument_type + measured_variable + available_date + decommission_date + related_identifier + alternative_identifier + instrument_resource_type + funding_reference views ] } end @@ -98,13 +109,24 @@ expect(row[18]).to eq version.based_near expect(row[19]).to eq version.related_url expect(row[20]).to eq version.source + expect(row[21]).to eq version.owner + expect(row[22]).to eq version.manufacturer + expect(row[23]).to eq version.model + expect(row[24]).to eq version.instrument_type + expect(row[25]).to eq version.measured_variable + expect(row[26]).to eq version.available_date + expect(row[27]).to eq version.decommission_date + expect(row[28]).to eq version.related_identifier + expect(row[29]).to eq version.alternative_identifier + expect(row[30]).to eq version.instrument_resource_type + expect(row[31]).to eq version.funding_reference end # Spot check view statistics - expect(yielded_rows[0][21]).to eq 6 - expect(yielded_rows[1][21]).to eq 0 - expect(yielded_rows[2][21]).to eq 1 - expect(yielded_rows[3][21]).to eq 0 + expect(yielded_rows[0][32]).to eq 6 + expect(yielded_rows[1][32]).to eq 0 + expect(yielded_rows[2][32]).to eq 1 + expect(yielded_rows[3][32]).to eq 0 end end end diff --git a/spec/services/api/v1/work_publisher_spec.rb b/spec/services/api/v1/work_publisher_spec.rb index b629d3da2..8a1a28805 100644 --- a/spec/services/api/v1/work_publisher_spec.rb +++ b/spec/services/api/v1/work_publisher_spec.rb @@ -255,7 +255,6 @@ 'Versions description is required to publish the work', "Versions creators can't be blank", "Versions file resources can't be blank", - 'Versions published date is not a valid date in EDTF format', 'Versions published date is required to publish the work', 'Versions visibility cannot be private', "Work type can't be blank", diff --git a/spec/services/edtf_date_spec.rb b/spec/services/edtf_date_spec.rb index 080b7382e..31458a816 100644 --- a/spec/services/edtf_date_spec.rb +++ b/spec/services/edtf_date_spec.rb @@ -9,6 +9,10 @@ '1999-uu-uu' => true, '1984?-01~' => true, + # Blank values + nil => true, + '' => true, + # Valid Ruby dates, but invalid EDTF dates 'January 21, 2019' => false, 'January' => false, @@ -16,8 +20,6 @@ # Invalid values 'asdf' => false, - nil => false, - '' => false, 'January 41, 2019' => false }.each do |date, expected_value| diff --git a/spec/support/feature_helpers/dashboard_form.rb b/spec/support/feature_helpers/dashboard_form.rb index 53eedac3c..8f28ba9fc 100644 --- a/spec/support/feature_helpers/dashboard_form.rb +++ b/spec/support/feature_helpers/dashboard_form.rb @@ -19,6 +19,11 @@ def self.fill_in_minimal_work_details_for_data_and_code_draft(work_version_metad select Work::Types.display('dataset'), from: 'work_version_work_attributes_work_type' end + def self.fill_in_minimal_work_details_for_instrument_draft(work_version_metadata) + fill_in 'work_version_title', with: work_version_metadata[:title] + select Work::Types.display('instrument'), from: 'work_version_work_attributes_work_type' + end + def self.fill_in_common_work_details(work_version_metadata) fill_in 'work_version_description', with: work_version_metadata[:description] fill_in 'work_version_published_date', with: work_version_metadata[:published_date] @@ -45,6 +50,13 @@ def self.fill_in_data_and_code_work_details(work_version_metadata) fill_in 'work_version_source', with: work_version_metadata[:source] end + def self.fill_in_instrument_work_details(work_version_metadata) + fill_in 'work_version_description', with: work_version_metadata[:description] + fill_in 'work_version_published_date', with: work_version_metadata[:published_date] + fill_in 'work_version_owner', with: work_version_metadata[:owner] + fill_in 'work_version_model', with: work_version_metadata[:model] + end + def self.fill_in_scholarly_works_work_details(work_version_metadata) fill_in_common_work_details(work_version_metadata) fill_in 'work_version_identifier', with: work_version_metadata[:identifier]