hyrax-doi 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0263fd4d11d35e30f48410437354a6604f0726ddfeb13791062faf174c85d81
4
- data.tar.gz: 7db8943b4fa0b9960572ad3dba14f4f6bb069af024338033b5260ba74aac4450
3
+ metadata.gz: 9e91c07abad2fa33a98363ee05c8b3e2bf8c217161226d338e233772fb0941b8
4
+ data.tar.gz: bbf399c0250b3e073b2c11563d5f21ecf370d80a24eb88df1e1ade1186670946
5
5
  SHA512:
6
- metadata.gz: 69950241eb6d5511544d937cd87cdb94351ec171ebc94e7ad6f4dc91a16cd95be5263dea80d366ff431c6e79ba47bc28fd0b89e435078d8d199fc5caa8f7d2eb
7
- data.tar.gz: 789ac23699e1a9476c215350d1abef88dcf0fd5c596e2c7e76974d442fc4065d44ea9f0d8e26a895401635d93a5eb06f5bdc5b084189dfdd14702dff247b1266
6
+ metadata.gz: 3e32e969a6e8275ef71adf8a5012231f288b6126cb1ae3f765764fa2ad20217825aed3e8785b885aa9398dd03647f2ddef52f94c304d46b21f6dcf79a37d2410
7
+ data.tar.gz: 8a96dbf165655b4ceaf0cc79bc085ef1bc63bfaa272b09f21f95ee5f77c219cc66e8032cc9a5756012d714763ade05a53117f3541b443ab072d2d57ad0ed9663
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Hyrax::DOI
2
- Code: [![CircleCI](https://circleci.com/gh/ubiquitypress/hyrax-doi.svg?style=svg)](https://circleci.com/gh/ubiquitypress/hyrax-doi)
3
- [![Code Climate](https://codeclimate.com/github/ubiquitypress/hyrax-doi/badges/gpa.svg)](https://codeclimate.com/github/ubiquitypress/hyrax-doi)
2
+ Code: [![CircleCI](https://circleci.com/gh/samvera-labs/hyrax-doi.svg?style=svg)](https://circleci.com/gh/samvera-labs/hyrax-doi)
3
+ [![Code Climate](https://codeclimate.com/github/samvera-labs/hyrax-doi/badges/gpa.svg)](https://codeclimate.com/github/samvera-labs/hyrax-doi)
4
4
 
5
5
 
6
6
  Docs: [![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md)
@@ -10,6 +10,27 @@ Jump in: [![Slack Status](http://slack.samvera.org/badge.svg)](http://slack.samv
10
10
 
11
11
  Hyrax-doi is a Hyrax plugin that provides tools for working with DOIs including model attributes, minting, and fetching descriptive metadata.
12
12
 
13
+ ## Features
14
+ ### DOI Creation and Updating
15
+ DOIs are created and updated when a work of a DOI-enabled work type is saved. This happens in a background job using the [external identifier interface](https://github.com/samvera/hyrax/pull/4458) provided by Hyrax.
16
+
17
+ >Note: At this point only functionality for registering DOIs wtih DataCite is implemented but other registrars should be also be possible.
18
+
19
+ #### Draft DOI Creation (DataCite)
20
+ The deposit form has a button for creating a draft DOI without requiring submitting the form. This is useful if you need to know the DOI and embed it in the uploaded file(s).
21
+
22
+ #### DOI Status Support (DataCite)
23
+ The uploader is allowed to choose the DOI status (draft, registered, findable) they want for the work when it becomes public. If findable is chosen the DOI will remain as registered until the work become public.
24
+
25
+ #### Form Validation (DataCite)
26
+ Hyrax-doi will provide defaults or placeholders for fields which Hyrax doesn't require but which are mandatory for DataCite. In this case the uploader will be notified of the missing fields and given the opportunity of filling them in before submittign or of continuing with the defaults.
27
+
28
+ ### Form autofilling
29
+ When submitting a work with an existing DOI (like a scholarly article), the uploader can fill in the DOI and click a button to autofill the deposit form with metadata from the DOI. This is not limited to DataCite and works with DOIs from a variety of registrars (DataCite, CrossRef, JaLC, ISTIC, , etc.)
30
+
31
+ ### Metadata Crosswalking
32
+ DOI submission and form autofilling happens by crosswalking the work's metadata with DataCite's schema through the [bolognese gem](https://github.com/datacite/bolognese) which enables crosswalking with a number of metadata formats besides those required by DOI registars including RIS, BibTeX, Crosscite, and Schema.org.
33
+
13
34
  ## Compatibilty
14
35
  Hyrax-doi is compatible with Hyrax 2.9+ and tested with a [Hyrax 2.9.0 test application](https://github.com/ubiquitypress/hyrax_test_app) that mirrors the generated app used by Hyrax internally for testing.
15
36
 
@@ -25,41 +46,87 @@ And then execute:
25
46
  $ bundle
26
47
  ```
27
48
 
28
- Or install it yourself as:
29
- ```bash
30
- $ gem install hyrax-doi
49
+ Then run the install generator
50
+ ```
51
+ rails g hyrax:doi:install
52
+ ```
53
+ Use the `--datacite` flag if working with DataCite DOIs:
54
+ ```
55
+ rails g hyrax:doi:install --datacite
31
56
  ```
32
57
 
33
58
  ## Usage
34
59
 
35
- ### Setup work type for hyrax-doi
60
+ ### Enable DOI functionality for a work type
36
61
  Run the generator to add DOI support to a given work type:
37
62
  ```
38
63
  rails g hyrax:doi:add_to_work_type MyWorkType
39
64
  ```
65
+ Add the `--datacite` flag if creating DataCite DOIs:
66
+ ```
67
+ rails g hyrax:doi:add_to_work_type MyWorkType --datacite
68
+ ```
69
+
70
+ ### Configuration
71
+ After the install generator is run, Hyrax-doi can be configured in the `config/initializers/hyrax-doi.rb` initializer.
72
+
73
+ If your application does not already set `host` in `default_url_options`, you will need to configure it for creating full urls to work show pages to be registered with DOIs.
74
+
75
+ DataCite credentials can either be set in environment variables (DATACITE_PREFIX, DATACITE_USERNAME, and DATACITE_PASSWORD) or set in the initializer. Hyrax-doi defaults to using DataCite's test environment but can be switched to the production environment by setting the mode:
76
+ ```
77
+ Hyrax::DOI::DataCiteRegistrar.mode = :production
78
+ ```
79
+
80
+ ### Using with Hyku
81
+ Hyrax-doi is currently implemented for a single-tenant Hyrax application with configuration shared application wide. Work to support per tenant configuration is under way and will live in its own engine or be contributed directly to Hyku.
40
82
 
41
83
  ## Development
42
84
 
85
+ ### Setting up Development Environment
86
+ After checking out the code, initialize the internal hyrax test application:
87
+ ```
88
+ git submodule init
89
+ git submodule update
90
+ ```
91
+
43
92
  ### Running Rake Tasks and Generators
44
- When working on this engine rake tasks from Hyku can be run by prepending the `app` namespace (e.g. `rake app:db:migrate`). Generators provided by rails or other gems/engines can be run like normal from this engine's root (e.g. `rails g job UbiquityExporter`).
93
+ When working on this engine rake tasks from Hyrax can be run by prepending the `app` namespace (e.g. `rake app:db:migrate`). Generators provided by rails or other gems/engines can be run like normal from this engine's root (e.g. `rails g job CheckDOIResolution`).
45
94
 
46
95
  ### Development Server
47
96
 
48
- To run a development server locally outside of docker do the following with each line in its own shell from the root of the engine:
97
+ To run a development server locally, start the required services using Docker Compose:
49
98
  ```
50
- solr_wrapper -v --config .solr_wrapper.yml
51
- fcrepo_wrapper -v --config .fcrepo_wrapper.yml
99
+ docker compose up -d
52
100
  bundle exec rails server -b 0.0.0.0
53
101
  ```
54
102
 
103
+ To stop the services:
104
+ ```
105
+ docker compose down
106
+ ```
107
+
55
108
  ### Testing
56
109
 
57
- Tests are run automatically on CircleCI with rubocop and codeclimate. These tests must pass before pull requests can be merged.
110
+ Tests are run automatically in CI with rubocop and codeclimate. These tests must pass before pull requests can be merged.
58
111
 
59
- To run the tests locally outside of docker do the following with each line in its own shell from the root of the engine:
112
+ To run the tests locally, start the test services using Docker Compose:
60
113
  ```
61
- solr_wrapper -v --config .solr_wrapper_test.yml
62
- fcrepo_wrapper -v --config .fcrepo_wrapper_test.yml
114
+ docker compose up -d
115
+ docker compose exec web bash
116
+ cd /app/samvera/hyrax-doi
117
+ bundle
63
118
  bundle exec rspec
64
119
  ```
65
- You shouldn't need to run anything from inside `spec/internal_test_hyrax` unless explicitly told to do so.
120
+
121
+ ### Linting
122
+
123
+ To run the linter locally, start the test services using Docker Compose:
124
+ ```
125
+ docker compose up -d
126
+ docker compose exec web bash
127
+ cd /app/samvera/hyrax-doi
128
+ bundle
129
+ bundle exec rubocop
130
+ ```
131
+
132
+ You shouldn't need to run anything from inside `vendor/engines/hyrax` unless explicitly told to do so.
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
15
15
  rdoc.rdoc_files.include('lib/**/*.rb')
16
16
  end
17
17
 
18
- APP_RAKEFILE = File.expand_path("spec/internal_test_hyrax/Rakefile", __dir__)
18
+ APP_RAKEFILE = File.expand_path("vendor/engines/hyrax/.dassie/Rakefile", __dir__)
19
19
  load 'rails/tasks/engine.rake'
20
20
 
21
21
  load 'rails/tasks/statistics.rake'
@@ -15,7 +15,9 @@ module Hyrax
15
15
  # env = Hyrax::Actors::Environment.new(object, ability, attributes)
16
16
  # last_actor = Hyrax::Actors::Terminator.new
17
17
  # stack.build(last_actor).create(env)
18
- class DOIActor < AbstractActor
18
+ class DOIActor < BaseActor
19
+ delegate :destroy, to: :next_actor
20
+
19
21
  ##
20
22
  # @return [Boolean]
21
23
  #
@@ -30,13 +32,17 @@ module Hyrax
30
32
  #
31
33
  # @see Hyrax::Actors::AbstractActor
32
34
  def update(env)
35
+ # Ensure that the work has any changed attributes persisted before we create the job
36
+ apply_save_data_to_curation_concern(env)
37
+ save(env)
38
+
33
39
  create_or_update_doi(env.curation_concern) && next_actor.update(env)
34
40
  end
35
41
 
36
42
  private
37
43
 
38
44
  def create_or_update_doi(work)
39
- return true unless doi_enabled_work_type?(work)
45
+ return true unless doi_enabled_work_type?(work) && Flipflop.enabled?(:doi_minting) && valid_public_status?(work)
40
46
 
41
47
  Hyrax::DOI::RegisterDOIJob.perform_later(work, registrar: work.doi_registrar.presence, registrar_opts: work.doi_registrar_opts)
42
48
  end
@@ -45,6 +51,12 @@ module Hyrax
45
51
  def doi_enabled_work_type?(work)
46
52
  work.class.ancestors.include? Hyrax::DOI::DOIBehavior
47
53
  end
54
+
55
+ # FIXME: Find a way to push this into the registrar since it is Datacite specific
56
+ # Check that requested doi_status_when_public is valid
57
+ def valid_public_status?(work)
58
+ !work.respond_to?(:doi_status_when_public) || work.doi_status_when_public.in?(Hyrax::DOI::DataCiteRegistrar::STATES)
59
+ end
48
60
  end
49
61
  end
50
62
  end
@@ -5,11 +5,18 @@ module Hyrax
5
5
  before_action :check_authorization
6
6
 
7
7
  def create_draft_doi
8
- draft_doi = mint_draft_doi
8
+ if Flipflop.enabled?(:doi_minting)
9
+ draft_doi = mint_draft_doi
9
10
 
10
- respond_to do |format|
11
- format.js { render js: autofill_field(doi_attribute_name, draft_doi), status: :created }
12
- format.json { render_json_response(response_type: :created, options: { data: draft_doi }) }
11
+ respond_to do |format|
12
+ format.js { render js: autofill_field(doi_attribute_name, draft_doi), status: :created }
13
+ format.json { render_json_response(response_type: :created, options: { data: draft_doi }) }
14
+ end
15
+ else
16
+ respond_to do |format|
17
+ format.js { render plain: I18n.t("errors.doi_minting.disabled"), status: :internal_error }
18
+ format.json { render_json_response(response_type: :internal_error, message: I18n.t("errors.doi_minting.disabled")) }
19
+ end
13
20
  end
14
21
  rescue Hyrax::DOI::DataCiteClient::Error => e
15
22
  respond_to do |format|
@@ -42,7 +49,11 @@ module Hyrax
42
49
 
43
50
  def doi_registrar
44
51
  # TODO: generalize this
45
- Hyrax::Identifier::Registrar.for(:datacite, {})
52
+ Hyrax::Identifier::Registrar.for(:datacite)
53
+ end
54
+
55
+ def use_sandbox
56
+ !doi_registrar.mode.equal?(:production)
46
57
  end
47
58
 
48
59
  def field_selector(attribute_name)
@@ -54,36 +65,41 @@ module Hyrax
54
65
  end
55
66
 
56
67
  def hyrax_work_from_doi(doi)
57
- meta = Bolognese::Metadata.new(input: doi)
68
+ # TODO: generalize this
69
+ meta = Bolognese::Metadata.new(input: doi,
70
+ sandbox: use_sandbox)
58
71
  # Check that a record was actually loaded
59
72
  raise Hyrax::DOI::NotFoundError, "DOI (#{doi}) could not be found." if meta.blank? || meta.doi.blank?
73
+ meta.types["hyrax"] = (params['curation_concern'] || 'GenericWork').camelize
60
74
  meta.hyrax_work
61
75
  end
62
76
 
63
77
  # TODO: Move this out to a partial that gets rendered?
64
78
  def autofill_js(doi)
65
79
  # TODO: Need to wipe old data or is this just supplemental?
66
- js = hyrax_work_from_doi(doi).attributes.collect { |k, v| autofill_field(k, v) }.reject(&:blank?).join("\n")
80
+ js = hyrax_work_from_doi(doi).attributes.collect { |k, v| autofill_field(k, v) }.compact_blank.join("\n")
67
81
  js << "document.location = '#metadata';"
68
82
  end
69
83
 
70
84
  # TODO: Move this out to a partial that gets rendered?
71
85
  def autofill_field(attribute_name, value)
72
86
  js = []
87
+ curation_concern = params[:curation_concern] || 'generic_work'
73
88
  # TODO: add error handling in the JS so an error doesn't leave the autofilling incomplete
74
89
  Array(value).each_with_index do |v, index|
75
90
  # Is this the right way to do this?
76
91
  # Need to be smarter to see if all repeated fields are filled before trying to create a new one by clicking?
77
92
  js << "document.querySelectorAll('#{field_selector(attribute_name)} button.add')[0].click();" unless index.zero?
78
- js << "document.querySelectorAll('#{field_selector(attribute_name)} .form-control')[#{index}].value = '#{helpers.escape_javascript(v)}';"
93
+ # Use the field ID directly - this is more reliable than complex selectors
94
+ js << "var field = document.getElementById('#{curation_concern}_#{attribute_name}'); if (field) { field.value = '#{helpers.escape_javascript(v)}'; }"
79
95
  end
80
- js.reject(&:blank?).join("\n")
96
+ js.compact_blank.join("\n")
81
97
  end
82
98
 
83
99
  # Override of Hyrax method (See https://github.com/samvera/hyrax/pull/4495)
84
100
  # render a json response for +response_type+
85
101
  def render_json_response(response_type: :success, message: nil, options: {})
86
- json_body = Hyrax::API.generate_response_body(response_type: response_type, message: message, options: options)
102
+ json_body = Hyrax::API.generate_response_body(response_type:, message:, options:)
87
103
  render json: json_body, status: Hyrax::API.default_responses[response_type][:code]
88
104
  end
89
105
  end
@@ -4,7 +4,6 @@ module Hyrax
4
4
  module WorkFormHelper
5
5
  def form_tabs_for(form:)
6
6
  if form.model_class.ancestors.include? Hyrax::DOI::DOIBehavior
7
- # TODO: Add check for feature flipper?
8
7
  super.prepend("doi")
9
8
  else
10
9
  super
@@ -4,7 +4,7 @@ module Hyrax
4
4
  module DOIBehavior
5
5
  extend ActiveSupport::Concern
6
6
 
7
- DOI_REGEX = /\A10\.\d{4,}(\.\d+)*\/[-._;():\/A-Za-z\d]+\z/.freeze
7
+ DOI_REGEX = /\A10\.\d{4,}(\.\d+)*\/[-._;():\/A-Za-z\d]+\z/
8
8
 
9
9
  included do
10
10
  property :doi, predicate: ::RDF::Vocab::BIBO.doi, multiple: true do |index|
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require 'bolognese'
3
-
4
2
  module Bolognese
5
3
  module Readers
6
4
  # Use this with Bolognese like the following:
@@ -74,11 +72,10 @@ module Bolognese
74
72
  end
75
73
 
76
74
  def read_hyrax_work_publication_year(meta)
77
- # FIXME: better parsing of free text dates...maybe using EDTF?
78
75
  date = meta.fetch("date_created", nil)&.first
79
76
  date ||= meta.fetch("date_uploaded", nil)
80
- Date.parse(date.to_s).year
81
- rescue Date::Error
77
+ Date.edtf(date.to_s).year
78
+ rescue StandardError
82
79
  Time.zone.today.year
83
80
  end
84
81
 
@@ -92,6 +89,7 @@ module Bolognese
92
89
 
93
90
  def read_hyrax_work_publisher(meta)
94
91
  # Fallback to ':unav' since this is a required field for datacite
92
+ # TODO: Should this default to application_name?
95
93
  parse_attributes(meta.fetch("publisher")).to_s.strip.presence || ":unav"
96
94
  end
97
95
  end
@@ -16,9 +16,9 @@ module Bolognese
16
16
  # FIXME: This may not roundtrip since datacite normalizes the creator name
17
17
  'creator' => creators&.pluck("name"),
18
18
  'contributor' => contributors&.pluck("name"),
19
- 'publisher' => Array(publisher),
19
+ 'publisher' => build_hyrax_work_publisher,
20
20
  'date_created' => Array(publication_year),
21
- 'description' => descriptions&.pluck("description"),
21
+ 'description' => build_hyrax_work_description,
22
22
  'keyword' => subjects&.pluck("subject")
23
23
  }
24
24
  hyrax_work_class = determine_hyrax_work_class
@@ -34,17 +34,47 @@ module Bolognese
34
34
  end
35
35
 
36
36
  def build_hyrax_work_class
37
- Class.new(ActiveFedora::Base).tap do |c|
38
- c.include ::Hyrax::WorkBehavior
39
- c.include ::Hyrax::DOI::DOIBehavior
37
+ @hyrax_work_class ||= begin
38
+ klass = Class.new(ActiveFedora::Base) do
39
+ def self.name
40
+ "Bolognese::Writers::DynamicHyraxWork"
41
+ end
42
+
43
+ def self.to_s
44
+ name
45
+ end
46
+ end
47
+ klass.include ::Hyrax::WorkBehavior
48
+ klass.include ::Hyrax::DOI::DOIBehavior
40
49
  # Put BasicMetadata include last since it finalizes the metadata schema
41
- c.include ::Hyrax::BasicMetadata
50
+ klass.include ::Hyrax::BasicMetadata
51
+ klass
42
52
  end
43
53
  end
44
54
 
45
55
  def build_hyrax_work_doi
46
56
  Array(doi&.sub('https://doi.org/', ''))
47
57
  end
58
+
59
+ def build_hyrax_work_description
60
+ return nil if descriptions.blank?
61
+ descriptions.pluck("description").map { |d| Array(d).join("\n") }
62
+ end
63
+
64
+ def build_hyrax_work_publisher
65
+ return [] if publisher.blank?
66
+ # For crossref data, publisher can be a hash like {"name" => "eLife Sciences Publications, Ltd"}
67
+ # For datacite data, publisher is usually a string
68
+ case publisher
69
+ when Hash
70
+ # Extract the actual publisher name
71
+ Array(publisher['name'])
72
+ when String
73
+ [publisher]
74
+ else
75
+ Array(publisher)
76
+ end
77
+ end
48
78
  end
49
79
  end
50
80
  end
@@ -6,7 +6,7 @@ module Hyrax
6
6
 
7
7
  TEST_BASE_URL = "https://api.test.datacite.org/"
8
8
  TEST_MDS_BASE_URL = "https://mds.test.datacite.org/"
9
- PRODUCTION_BASE_URL = "https://api.datacite.org"
9
+ PRODUCTION_BASE_URL = "https://api.datacite.org/"
10
10
  PRODUCTION_MDS_BASE_URL = "https://mds.datacite.org/"
11
11
 
12
12
  def initialize(username:, password:, prefix:, mode: :production)
@@ -20,7 +20,7 @@ module Hyrax
20
20
  # If you already have a DOI and want to register it as a draft then go through the normal process (put_metadata/register_url)
21
21
  def create_draft_doi
22
22
  # Use regular api instead of mds for metadata-less url-less draft doi creation
23
- response = connection.post('dois', draft_doi_payload.to_json, "Content-Type" => "application/json")
23
+ response = connection.post('dois', draft_doi_payload.to_json, "Content-Type" => "application/vnd.api+json")
24
24
  raise Error.new('Failed creating draft DOI', response) unless response.status == 201
25
25
 
26
26
  JSON.parse(response.body)['data']['id']
@@ -103,14 +103,14 @@ module Hyrax
103
103
 
104
104
  def connection
105
105
  Faraday.new(url: base_url) do |c|
106
- c.basic_auth(username, password)
106
+ c.try(:basic_auth) ? c.basic_auth(username, password) : c.request(:authorization, :basic, username, password)
107
107
  c.adapter(Faraday.default_adapter)
108
108
  end
109
109
  end
110
110
 
111
111
  def mds_connection
112
112
  Faraday.new(url: mds_base_url) do |c|
113
- c.basic_auth(username, password)
113
+ c.try(:basic_auth) ? c.basic_auth(username, password) : c.request(:authorization, :basic, username, password)
114
114
  c.adapter(Faraday.default_adapter)
115
115
  end
116
116
  end
@@ -126,12 +126,13 @@ module Hyrax
126
126
  }
127
127
  end
128
128
 
129
+ # Ensre that `mode` is not a string
129
130
  def base_url
130
- mode == :production ? PRODUCTION_BASE_URL : TEST_BASE_URL
131
+ mode&.to_sym == :production ? PRODUCTION_BASE_URL : TEST_BASE_URL
131
132
  end
132
133
 
133
134
  def mds_base_url
134
- mode == :production ? PRODUCTION_MDS_BASE_URL : TEST_MDS_BASE_URL
135
+ mode&.to_sym == :production ? PRODUCTION_MDS_BASE_URL : TEST_MDS_BASE_URL
135
136
  end
136
137
  end
137
138
  end
@@ -62,7 +62,7 @@ module Hyrax
62
62
  end
63
63
 
64
64
  def client
65
- @client ||= Hyrax::DOI::DataCiteClient.new(username: self.username, password: self.password, prefix: self.prefix, mode: mode)
65
+ @client ||= Hyrax::DOI::DataCiteClient.new(username: self.username, password: self.password, prefix: self.prefix, mode:)
66
66
  end
67
67
 
68
68
  # Do the heavy lifting of submitting the metadata, registering the url, and ensuring the correct status
@@ -1,28 +1,39 @@
1
+ <%# TODO: determine these from actual DataCite data instead of the intention field stored in fedora %>
2
+ <% disable_do_not_mint = @curation_concern.doi_status_when_public != nil %>
3
+ <% disable_draft = @curation_concern.doi_status_when_public.in?(['registered','findable']) %>
4
+
1
5
  <div>
2
- <%# TODO: Make this appear as singular %>
3
- <%= render_edit_field_partial('doi', f: f) %>
6
+ <%# Render DOI input as a single field even though it is stored as multivalued %>
7
+ <%= f.input :doi, input_html: { value: @curation_concern.doi.first,
8
+ name: "#{f.object.model_name.param_key}[doi][]",
9
+ style: "max-width: 40em" } %>
4
10
 
5
- <%= link_to "Create draft DOI",
6
- Hyrax::DOI::Engine.routes.url_helpers.create_draft_doi_path,
7
- remote: true,
8
- method: :get,
9
- data: {
10
- disable_with: "Creating draft DOI...",
11
- params: {
12
- curation_concern: curation_concern.class.name.underscore,
13
- attribute: 'doi'
14
- }
15
- },
16
- class: 'btn btn-default',
17
- id: 'doi-create-draft-btn' %>
11
+ <%# Only show an actionable button if the work doesn't have a DOI already %>
12
+ <% if @curation_concern.doi.blank? && Flipflop.enabled?(:doi_minting) %>
13
+ <%= link_to "Create draft DOI",
14
+ Hyrax::DOI::Engine.routes.url_helpers.create_draft_doi_path,
15
+ remote: true,
16
+ method: :get,
17
+ data: {
18
+ disable_with: t("hyrax.works.form.mint.button.disable_with"),
19
+ params: {
20
+ curation_concern: @curation_concern.class.name.underscore,
21
+ attribute: 'doi'
22
+ }
23
+ },
24
+ class: 'btn btn-default',
25
+ id: 'doi-create-draft-btn' %>
26
+ <% else %>
27
+ <div id='doi-create-draft-btn' class='btn btn-default' disabled="true">Create draft DOI</div>
28
+ <% end %>
18
29
 
19
30
  <%= link_to "Autofill form",
20
31
  Hyrax::DOI::Engine.routes.url_helpers.autofill_path,
21
32
  remote: true,
22
33
  method: :get,
23
34
  data: {
24
- confirm: "This operation is destructive and will replace any information already filled in on this form.",
25
- disable_with: "Autofilling form...",
35
+ confirm: t("hyrax.works.form.autofill.button.confirm"),
36
+ disable_with: t("hyrax.works.form.autofill.button.disable_with"),
26
37
  params: { curation_concern: curation_concern.class.name.underscore }
27
38
  },
28
39
  class: 'btn btn-primary',
@@ -30,28 +41,30 @@
30
41
 
31
42
  <br/><br/><br/>
32
43
 
33
- <fieldset class="set-doi-status-when-public">
34
- <label class="control-label">DOI status when work is public</label>
44
+ <% if Flipflop.enabled?(:doi_minting) %>
45
+ <fieldset class="set-doi-status-when-public">
46
+ <label class="control-label">DOI status when work is public</label>
35
47
 
36
- <div class="form-group" style="margin-left: 20px">
37
- <label class="radio" style="font-weight: normal">
38
- <%= f.radio_button :doi_status_when_public, '', style: 'margin-top: 0px;' %>
39
- Do not mint
40
- </label>
41
- <label class="radio" style="font-weight: normal">
42
- <%= f.radio_button :doi_status_when_public, 'draft', style: 'margin-top: 0px;' %>
43
- Draft
44
- </label>
45
- <label class="radio" style="font-weight: normal">
46
- <%= f.radio_button :doi_status_when_public, 'registered', style: 'margin-top: 0px;' %>
47
- Registered
48
- </label>
49
- <label class="radio" style="font-weight: normal">
50
- <%= f.radio_button :doi_status_when_public, 'findable', style: 'margin-top: 0px;' %>
51
- Findable
52
- </label>
53
- </div>
54
- </fieldset>
48
+ <div class="form-group" style="margin-left: 20px">
49
+ <label class="radio" style="font-weight: normal">
50
+ <%= f.radio_button :doi_status_when_public, '', disabled: disable_do_not_mint, style: 'margin-top: 0px;' %>
51
+ Do not mint
52
+ </label>
53
+ <label class="radio" style="font-weight: normal">
54
+ <%= f.radio_button :doi_status_when_public, 'draft', disabled: disable_draft, style: 'margin-top: 0px;' %>
55
+ Draft
56
+ </label>
57
+ <label class="radio" style="font-weight: normal">
58
+ <%= f.radio_button :doi_status_when_public, 'registered', style: 'margin-top: 0px;' %>
59
+ Registered
60
+ </label>
61
+ <label class="radio" style="font-weight: normal">
62
+ <%= f.radio_button :doi_status_when_public, 'findable', style: 'margin-top: 0px;' %>
63
+ Findable
64
+ </label>
65
+ </div>
66
+ </fieldset>
67
+ <% end %>
55
68
  </div>
56
69
 
57
70
  <script type="text/javascript">
@@ -59,7 +72,7 @@
59
72
  // Note this uses jQuery since we're using jquery-ujs still
60
73
  // There is probably a better way to do this but this works for now
61
74
  $("#doi-autofill-btn").on("ajax:beforeSend", function(e, xhr, settings) {
62
- doi = $('#generic_work_doi').val()
75
+ doi = $('<%= "##{curation_concern.class.name.underscore}_doi" %>').val()
63
76
  settings.url = settings.url + "&doi=" + encodeURIComponent(doi)
64
77
  });
65
78
 
@@ -67,7 +80,37 @@
67
80
  alert(xhr.responseText);
68
81
  });
69
82
 
83
+ // To override this action and add your own ajax error listener, you can use jQuery's `off` method,
84
+ // before registering your own listener. E.g. $("#doi-autofill-btn").off("ajax:error")
70
85
  $("#doi-autofill-btn").on("ajax:error", function(e, xhr, status, error) {
71
86
  alert(xhr.responseText);
72
87
  });
88
+
89
+ // Force the user to confirm using fallback defaults when DataCite mandatory fields
90
+ // not filled in on the deposit form. This only applies when the DOI is set to become
91
+ // registered or findable. Let drafts be drafts.
92
+ $(document).ready(function() {
93
+ curation_concern = '<%= curation_concern.class.name.underscore %>';
94
+ document.getElementById('with_files_submit').addEventListener("click", function(event){
95
+ if (["findable", "registered"].indexOf(document.querySelector('input[name="' + curation_concern + '[doi_status_when_public]"]:checked').value) < 0)
96
+ return;
97
+
98
+ const empty_fields = [];
99
+ if (document.querySelector('.' + curation_concern + '_title .form-control').value == "")
100
+ empty_fields.push("Title")
101
+ if (document.querySelector('.' + curation_concern + '_creator .form-control').value == "")
102
+ empty_fields.push("Creator")
103
+ if (document.querySelector('.' + curation_concern + '_publisher .form-control').value == "")
104
+ empty_fields.push("Publisher")
105
+ if (document.querySelector('.' + curation_concern + '_date_created .form-control').value == "")
106
+ empty_fields.push("Date Created")
107
+ if (empty_fields.length == 0)
108
+ return;
109
+
110
+ if(!window.confirm("DataCite DOI mandatory fields ("+ empty_fields.join(', ') +") are missing. Placeholder values will be submitted to DataCite instead. Do you want to proceed?")){
111
+ event.preventDefault();
112
+ event.stopImmediatePropagation();
113
+ }
114
+ }, false);
115
+ });
73
116
  </script>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Flipflop.configure do
4
+ feature :doi_minting,
5
+ default: true,
6
+ description: "Toggle the DOI minting for this tenant"
7
+ end
@@ -3,5 +3,15 @@ en:
3
3
  hyrax:
4
4
  works:
5
5
  form:
6
+ mint:
7
+ button:
8
+ disable_with: Creating draft DOI...
9
+ autofill:
10
+ button:
11
+ disable_with: Autofilling form...
12
+ confirm: This operation is destructive and will replace any information already filled in on this form.
6
13
  tab:
7
- doi: DOI
14
+ doi: DOI
15
+ errors:
16
+ doi_minting:
17
+ disabled: DOI minting is disabled by your administrator
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Hyrax
3
4
  module DOI
4
5
  class Engine < ::Rails::Engine
@@ -13,6 +14,11 @@ module Hyrax
13
14
  end
14
15
  end
15
16
 
17
+ # Allow flipflop to load config/features.rb from the Hyrax gem:
18
+ initializer 'configure' do
19
+ Flipflop::FeatureLoader.current.append(self)
20
+ end
21
+
16
22
  config.after_initialize do
17
23
  Hyrax::CurationConcern.actor_factory.use Hyrax::Actors::DOIActor
18
24
 
@@ -20,8 +26,15 @@ module Hyrax
20
26
  Bolognese::Metadata.prepend Bolognese::Readers::HyraxWorkReader
21
27
  Bolognese::Metadata.prepend Bolognese::Writers::HyraxWorkWriter
22
28
 
23
- # Prepend our views so they have precedence
24
- ActionController::Base.prepend_view_path(paths['app/views'].existent)
29
+ # Prepend our views in front of Hyrax but after the main app, so they have precedence
30
+ # but can still be overridden
31
+ my_engine_root = Hyrax::DOI::Engine.root.to_s
32
+ hyrax_engine_root = Hyrax::Engine.root.to_s
33
+ paths = ActionController::Base.view_paths.collect(&:to_s)
34
+ hyrax_view_path = paths.detect { |path| path.match(%r{^#{hyrax_engine_root}}) }
35
+ paths.insert(paths.index(hyrax_view_path), File.join(my_engine_root, 'app', 'views')) if hyrax_view_path
36
+
37
+ ActionController::Base.view_paths = paths.uniq
25
38
  end
26
39
  end
27
40
  end
@@ -3,7 +3,11 @@ RSpec.shared_examples "a DataCite DOI-enabled presenter" do
3
3
  subject { presenter }
4
4
 
5
5
  let(:presenter) { presenter_class.new(solr_document, nil, nil) }
6
- let(:solr_document) { instance_double(solr_document_class) }
6
+ let(:solr_document) do
7
+ solr_double = instance_double(solr_document_class)
8
+ allow(solr_double).to receive(:flexible?).and_return(false)
9
+ solr_double
10
+ end
7
11
 
8
12
  it { is_expected.to delegate_method(:doi_status_when_public).to(:solr_document) }
9
13
 
@@ -3,7 +3,11 @@ RSpec.shared_examples "a DOI-enabled presenter" do
3
3
  subject { presenter }
4
4
 
5
5
  let(:presenter) { presenter_class.new(solr_document, nil, nil) }
6
- let(:solr_document) { instance_double(solr_document_class) }
6
+ let(:solr_document) do
7
+ solr_double = instance_double(solr_document_class)
8
+ allow(solr_double).to receive(:flexible?).and_return(false)
9
+ solr_double
10
+ end
7
11
 
8
12
  describe 'doi' do
9
13
  let(:doi) { '10.1234/abc' }
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Hyrax
3
3
  module DOI
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.0'
5
5
  end
6
6
  end
data/lib/hyrax/doi.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require "hyrax/doi/engine"
3
3
  require "hyrax/doi/errors"
4
+ require "flipflop"
4
5
 
5
6
  module Hyrax
6
7
  module DOI
metadata CHANGED
@@ -1,69 +1,102 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyrax-doi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Colvard
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2020-09-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 5.2.4
20
16
  - - ">="
21
17
  - !ruby/object:Gem::Version
22
18
  version: 5.2.4.3
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '8.0'
23
22
  type: :runtime
24
23
  prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
26
25
  requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: 5.2.4
30
26
  - - ">="
31
27
  - !ruby/object:Gem::Version
32
28
  version: 5.2.4.3
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '8.0'
33
32
  - !ruby/object:Gem::Dependency
34
33
  name: hyrax
35
34
  requirement: !ruby/object:Gem::Requirement
36
35
  requirements:
37
- - - "~>"
36
+ - - ">="
38
37
  - !ruby/object:Gem::Version
39
38
  version: '2.9'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '6.0'
40
42
  type: :runtime
41
43
  prerelease: false
42
44
  version_requirements: !ruby/object:Gem::Requirement
43
45
  requirements:
44
- - - "~>"
46
+ - - ">="
45
47
  - !ruby/object:Gem::Version
46
48
  version: '2.9'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '6.0'
47
52
  - !ruby/object:Gem::Dependency
48
- name: bolognese
53
+ name: flipflop
49
54
  requirement: !ruby/object:Gem::Requirement
50
55
  requirements:
51
56
  - - "~>"
52
57
  - !ruby/object:Gem::Version
53
- version: '1.8'
58
+ version: '2.3'
59
+ type: :runtime
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '2.3'
66
+ - !ruby/object:Gem::Dependency
67
+ name: bolognese
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
54
70
  - - ">="
55
71
  - !ruby/object:Gem::Version
56
72
  version: 1.8.6
73
+ - - "<"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
57
76
  type: :runtime
58
77
  prerelease: false
59
78
  version_requirements: !ruby/object:Gem::Requirement
60
79
  requirements:
61
- - - "~>"
62
- - !ruby/object:Gem::Version
63
- version: '1.8'
64
80
  - - ">="
65
81
  - !ruby/object:Gem::Version
66
82
  version: 1.8.6
83
+ - - "<"
84
+ - !ruby/object:Gem::Version
85
+ version: '3.0'
86
+ - !ruby/object:Gem::Dependency
87
+ name: addressable
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '='
91
+ - !ruby/object:Gem::Version
92
+ version: 2.8.1
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '='
98
+ - !ruby/object:Gem::Version
99
+ version: 2.8.1
67
100
  - !ruby/object:Gem::Dependency
68
101
  name: ammeter
69
102
  requirement: !ruby/object:Gem::Requirement
@@ -190,20 +223,6 @@ dependencies:
190
223
  - - ">="
191
224
  - !ruby/object:Gem::Version
192
225
  version: '0'
193
- - !ruby/object:Gem::Dependency
194
- name: webdrivers
195
- requirement: !ruby/object:Gem::Requirement
196
- requirements:
197
- - - "~>"
198
- - !ruby/object:Gem::Version
199
- version: '4.0'
200
- type: :development
201
- prerelease: false
202
- version_requirements: !ruby/object:Gem::Requirement
203
- requirements:
204
- - - "~>"
205
- - !ruby/object:Gem::Version
206
- version: '4.0'
207
226
  - !ruby/object:Gem::Dependency
208
227
  name: webmock
209
228
  requirement: !ruby/object:Gem::Requirement
@@ -273,6 +292,7 @@ files:
273
292
  - app/services/hyrax/doi/datacite_registrar.rb
274
293
  - app/views/hyrax/base/_attribute_rows.html.erb
275
294
  - app/views/hyrax/base/_form_doi.html.erb
295
+ - config/features.rb
276
296
  - config/locales/hyrax_doi.en.yml
277
297
  - config/routes.rb
278
298
  - lib/generators/hyrax/doi/add_to_work_type_generator.rb
@@ -297,7 +317,6 @@ licenses:
297
317
  - MIT
298
318
  metadata:
299
319
  allowed_push_host: https://rubygems.org
300
- post_install_message:
301
320
  rdoc_options: []
302
321
  require_paths:
303
322
  - lib
@@ -312,8 +331,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
312
331
  - !ruby/object:Gem::Version
313
332
  version: '0'
314
333
  requirements: []
315
- rubygems_version: 3.1.2
316
- signing_key:
334
+ rubygems_version: 3.6.9
317
335
  specification_version: 4
318
336
  summary: Hyrax plugin for working with DOIs.
319
337
  test_files: []