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') %>
+
+ - <%= t('dashboard.form.details.readme.format') %><%= link_to t('dashboard.form.details.readme.documentation'), 'https://docs.scholarsphere.psu.edu/guides/writing-readme/' %>.
+ - <%= t('dashboard.form.details.image.format') %>
+ - <%= t('dashboard.form.details.image.zip') %>
+
+
<% 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 @@
-
+
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]