hyrax-doi 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +65 -0
- data/Rakefile +23 -0
- data/app/actors/hyrax/actors/doi_actor.rb +50 -0
- data/app/assets/config/hyrax_doi_manifest.js +2 -0
- data/app/assets/javascripts/hyrax/doi/application.js +15 -0
- data/app/assets/stylesheets/hyrax/doi/application.css +15 -0
- data/app/controllers/hyrax/doi/application_controller.rb +15 -0
- data/app/controllers/hyrax/doi/hyrax_doi_controller.rb +91 -0
- data/app/forms/concerns/hyrax/doi/datacite_doi_form_behavior.rb +18 -0
- data/app/forms/concerns/hyrax/doi/doi_form_behavior.rb +18 -0
- data/app/helpers/hyrax/doi/helper_behavior.rb +9 -0
- data/app/helpers/hyrax/doi/work_form_helper.rb +15 -0
- data/app/helpers/hyrax/doi/work_show_helper.rb +12 -0
- data/app/jobs/hyrax/doi/application_job.rb +7 -0
- data/app/jobs/hyrax/doi/register_doi_job.rb +18 -0
- data/app/models/concerns/hyrax/doi/datacite_doi_behavior.rb +21 -0
- data/app/models/concerns/hyrax/doi/doi_behavior.rb +38 -0
- data/app/models/concerns/hyrax/doi/solr_document/datacite_doi_behavior.rb +14 -0
- data/app/models/concerns/hyrax/doi/solr_document/doi_behavior.rb +14 -0
- data/app/presenters/concerns/hyrax/doi/datacite_doi_presenter_behavior.rb +20 -0
- data/app/presenters/concerns/hyrax/doi/doi_presenter_behavior.rb +12 -0
- data/app/services/bolognese/readers/hyrax_work_reader.rb +99 -0
- data/app/services/bolognese/writers/hyrax_work_writer.rb +50 -0
- data/app/services/hyrax/doi/datacite_client.rb +138 -0
- data/app/services/hyrax/doi/datacite_registrar.rb +121 -0
- data/app/views/hyrax/base/_attribute_rows.html.erb +18 -0
- data/app/views/hyrax/base/_form_doi.html.erb +73 -0
- data/config/locales/hyrax_doi.en.yml +7 -0
- data/config/routes.rb +5 -0
- data/lib/generators/hyrax/doi/add_to_work_type_generator.rb +97 -0
- data/lib/generators/hyrax/doi/install_generator.rb +74 -0
- data/lib/generators/hyrax/doi/templates/config/initializers/hyrax-doi.rb +15 -0
- data/lib/hyrax/doi.rb +9 -0
- data/lib/hyrax/doi/engine.rb +28 -0
- data/lib/hyrax/doi/errors.rb +8 -0
- data/lib/hyrax/doi/spec/shared_specs.rb +9 -0
- data/lib/hyrax/doi/spec/shared_specs/datacite_doi_behavior.rb +40 -0
- data/lib/hyrax/doi/spec/shared_specs/datacite_doi_form_behavior.rb +17 -0
- data/lib/hyrax/doi/spec/shared_specs/datacite_doi_presenter_behavior.rb +39 -0
- data/lib/hyrax/doi/spec/shared_specs/doi_behavior.rb +63 -0
- data/lib/hyrax/doi/spec/shared_specs/doi_form_behavior.rb +17 -0
- data/lib/hyrax/doi/spec/shared_specs/doi_presenter_behavior.rb +19 -0
- data/lib/hyrax/doi/spec/shared_specs/solr_document/datacite_doi_behavior.rb +20 -0
- data/lib/hyrax/doi/spec/shared_specs/solr_document/doi_behavior.rb +20 -0
- data/lib/hyrax/doi/version.rb +6 -0
- data/lib/tasks/hyrax/doi_tasks.rake +5 -0
- metadata +319 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d0263fd4d11d35e30f48410437354a6604f0726ddfeb13791062faf174c85d81
|
4
|
+
data.tar.gz: 7db8943b4fa0b9960572ad3dba14f4f6bb069af024338033b5260ba74aac4450
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 69950241eb6d5511544d937cd87cdb94351ec171ebc94e7ad6f4dc91a16cd95be5263dea80d366ff431c6e79ba47bc28fd0b89e435078d8d199fc5caa8f7d2eb
|
7
|
+
data.tar.gz: 789ac23699e1a9476c215350d1abef88dcf0fd5c596e2c7e76974d442fc4065d44ea9f0d8e26a895401635d93a5eb06f5bdc5b084189dfdd14702dff247b1266
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
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)
|
4
|
+
|
5
|
+
|
6
|
+
Docs: [![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md)
|
7
|
+
[![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)
|
8
|
+
|
9
|
+
Jump in: [![Slack Status](http://slack.samvera.org/badge.svg)](http://slack.samvera.org/)
|
10
|
+
|
11
|
+
Hyrax-doi is a Hyrax plugin that provides tools for working with DOIs including model attributes, minting, and fetching descriptive metadata.
|
12
|
+
|
13
|
+
## Compatibilty
|
14
|
+
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
|
+
|
16
|
+
## Installation
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'hyrax-doi'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
```bash
|
25
|
+
$ bundle
|
26
|
+
```
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
```bash
|
30
|
+
$ gem install hyrax-doi
|
31
|
+
```
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
### Setup work type for hyrax-doi
|
36
|
+
Run the generator to add DOI support to a given work type:
|
37
|
+
```
|
38
|
+
rails g hyrax:doi:add_to_work_type MyWorkType
|
39
|
+
```
|
40
|
+
|
41
|
+
## Development
|
42
|
+
|
43
|
+
### 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`).
|
45
|
+
|
46
|
+
### Development Server
|
47
|
+
|
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:
|
49
|
+
```
|
50
|
+
solr_wrapper -v --config .solr_wrapper.yml
|
51
|
+
fcrepo_wrapper -v --config .fcrepo_wrapper.yml
|
52
|
+
bundle exec rails server -b 0.0.0.0
|
53
|
+
```
|
54
|
+
|
55
|
+
### Testing
|
56
|
+
|
57
|
+
Tests are run automatically on CircleCI with rubocop and codeclimate. These tests must pass before pull requests can be merged.
|
58
|
+
|
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:
|
60
|
+
```
|
61
|
+
solr_wrapper -v --config .solr_wrapper_test.yml
|
62
|
+
fcrepo_wrapper -v --config .fcrepo_wrapper_test.yml
|
63
|
+
bundle exec rspec
|
64
|
+
```
|
65
|
+
You shouldn't need to run anything from inside `spec/internal_test_hyrax` unless explicitly told to do so.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rdoc/task'
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
12
|
+
rdoc.title = 'Hyrax::DOI'
|
13
|
+
rdoc.options << '--line-numbers'
|
14
|
+
rdoc.rdoc_files.include('README.md')
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
APP_RAKEFILE = File.expand_path("spec/internal_test_hyrax/Rakefile", __dir__)
|
19
|
+
load 'rails/tasks/engine.rake'
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module Actors
|
4
|
+
##
|
5
|
+
# An actor that registers a DOI using the configured registar
|
6
|
+
# This actor should come after the model actor which saves the work
|
7
|
+
#
|
8
|
+
# @example use in middleware
|
9
|
+
# stack = ActionDispatch::MiddlewareStack.new.tap do |middleware|
|
10
|
+
# # middleware.use OtherMiddleware
|
11
|
+
# middleware.use Hyrax::Actors::DOIActor
|
12
|
+
# # middleware.use MoreMiddleware
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# env = Hyrax::Actors::Environment.new(object, ability, attributes)
|
16
|
+
# last_actor = Hyrax::Actors::Terminator.new
|
17
|
+
# stack.build(last_actor).create(env)
|
18
|
+
class DOIActor < AbstractActor
|
19
|
+
##
|
20
|
+
# @return [Boolean]
|
21
|
+
#
|
22
|
+
# @see Hyrax::Actors::AbstractActor
|
23
|
+
def create(env)
|
24
|
+
# Assume the model actor has already run and saved the work
|
25
|
+
create_or_update_doi(env.curation_concern) && next_actor.create(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# @return [Boolean]
|
30
|
+
#
|
31
|
+
# @see Hyrax::Actors::AbstractActor
|
32
|
+
def update(env)
|
33
|
+
create_or_update_doi(env.curation_concern) && next_actor.update(env)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def create_or_update_doi(work)
|
39
|
+
return true unless doi_enabled_work_type?(work)
|
40
|
+
|
41
|
+
Hyrax::DOI::RegisterDOIJob.perform_later(work, registrar: work.doi_registrar.presence, registrar_opts: work.doi_registrar_opts)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check if work is DOI enabled
|
45
|
+
def doi_enabled_work_type?(work)
|
46
|
+
work.class.ancestors.include? Hyrax::DOI::DOIBehavior
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require rails-ujs
|
14
|
+
//= require activestorage
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
protect_from_forgery with: :exception
|
6
|
+
|
7
|
+
def self.search_state_class=(*)
|
8
|
+
# no-op to make Hyrax::Controller happy
|
9
|
+
end
|
10
|
+
|
11
|
+
# Include after search_state_class is defined since Hyrax::Controller calls it
|
12
|
+
include Hyrax::Controller
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
class HyraxDOIController < ApplicationController
|
5
|
+
before_action :check_authorization
|
6
|
+
|
7
|
+
def create_draft_doi
|
8
|
+
draft_doi = mint_draft_doi
|
9
|
+
|
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 }) }
|
13
|
+
end
|
14
|
+
rescue Hyrax::DOI::DataCiteClient::Error => e
|
15
|
+
respond_to do |format|
|
16
|
+
format.js { render plain: e.message, status: :internal_server_error }
|
17
|
+
format.json { render_json_response(response_type: :internal_error, message: e.full_message) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def autofill
|
22
|
+
doi = params['doi']
|
23
|
+
|
24
|
+
respond_to do |format|
|
25
|
+
format.js { render js: autofill_js(doi), status: :ok }
|
26
|
+
end
|
27
|
+
rescue Hyrax::DOI::NotFoundError => e
|
28
|
+
respond_to do |format|
|
29
|
+
format.js { render plain: e.message, status: :internal_server_error }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def check_authorization
|
36
|
+
raise Hydra::AccessDenied unless current_ability.can_create_any_work?
|
37
|
+
end
|
38
|
+
|
39
|
+
def mint_draft_doi
|
40
|
+
doi_registrar.mint_draft_doi
|
41
|
+
end
|
42
|
+
|
43
|
+
def doi_registrar
|
44
|
+
# TODO: generalize this
|
45
|
+
Hyrax::Identifier::Registrar.for(:datacite, {})
|
46
|
+
end
|
47
|
+
|
48
|
+
def field_selector(attribute_name)
|
49
|
+
".#{params[:curation_concern]}_#{attribute_name}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def doi_attribute_name
|
53
|
+
params[:attribute] || "doi"
|
54
|
+
end
|
55
|
+
|
56
|
+
def hyrax_work_from_doi(doi)
|
57
|
+
meta = Bolognese::Metadata.new(input: doi)
|
58
|
+
# Check that a record was actually loaded
|
59
|
+
raise Hyrax::DOI::NotFoundError, "DOI (#{doi}) could not be found." if meta.blank? || meta.doi.blank?
|
60
|
+
meta.hyrax_work
|
61
|
+
end
|
62
|
+
|
63
|
+
# TODO: Move this out to a partial that gets rendered?
|
64
|
+
def autofill_js(doi)
|
65
|
+
# 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")
|
67
|
+
js << "document.location = '#metadata';"
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO: Move this out to a partial that gets rendered?
|
71
|
+
def autofill_field(attribute_name, value)
|
72
|
+
js = []
|
73
|
+
# TODO: add error handling in the JS so an error doesn't leave the autofilling incomplete
|
74
|
+
Array(value).each_with_index do |v, index|
|
75
|
+
# Is this the right way to do this?
|
76
|
+
# Need to be smarter to see if all repeated fields are filled before trying to create a new one by clicking?
|
77
|
+
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)}';"
|
79
|
+
end
|
80
|
+
js.reject(&:blank?).join("\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
# Override of Hyrax method (See https://github.com/samvera/hyrax/pull/4495)
|
84
|
+
# render a json response for +response_type+
|
85
|
+
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)
|
87
|
+
render json: json_body, status: Hyrax::API.default_responses[response_type][:code]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module DataCiteDOIFormBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.terms += [:doi_status_when_public]
|
9
|
+
|
10
|
+
delegate :doi_status_when_public, to: :model
|
11
|
+
end
|
12
|
+
|
13
|
+
def secondary_terms
|
14
|
+
super - [:doi_status_when_public]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module DOIFormBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.terms += [:doi]
|
9
|
+
|
10
|
+
delegate :doi, to: :model
|
11
|
+
end
|
12
|
+
|
13
|
+
def secondary_terms
|
14
|
+
super - [:doi]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module WorkFormHelper
|
5
|
+
def form_tabs_for(form:)
|
6
|
+
if form.model_class.ancestors.include? Hyrax::DOI::DOIBehavior
|
7
|
+
# TODO: Add check for feature flipper?
|
8
|
+
super.prepend("doi")
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module WorkShowHelper
|
5
|
+
def render_doi?(presenter)
|
6
|
+
return false unless presenter.class.ancestors.include? Hyrax::DOI::DOIPresenterBehavior
|
7
|
+
return presenter.doi_status_when_public.in? [nil, 'registered', 'findable'] if presenter.class.ancestors.include? Hyrax::DOI::DataCiteDOIPresenterBehavior
|
8
|
+
true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
class RegisterDOIJob < ApplicationJob
|
5
|
+
queue_as Hyrax.config.ingest_queue_name
|
6
|
+
|
7
|
+
##
|
8
|
+
# @param model [ActiveFedora::Base]
|
9
|
+
# @param registrar [String] Note this is a string and not a symbol because ActiveJob cannot serialize a symbol
|
10
|
+
# @param registrar_opts [Hash]
|
11
|
+
def perform(model, registrar: Hyrax.config.identifier_registrars.keys.first, registrar_opts: {})
|
12
|
+
Hyrax::Identifier::Dispatcher
|
13
|
+
.for(registrar.to_sym, **registrar_opts)
|
14
|
+
.assign_for!(object: model, attribute: :doi)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module DataCiteDOIBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
property :doi_status_when_public, predicate: ::RDF::URI('http://samvera.org/ns/hyrax/doi#doi_status_when_public'), multiple: false do |index|
|
9
|
+
index.as :stored_sortable
|
10
|
+
end
|
11
|
+
|
12
|
+
validates :doi_status_when_public, inclusion: { in: Hyrax::DOI::DataCiteRegistrar::STATES }, allow_nil: true
|
13
|
+
end
|
14
|
+
|
15
|
+
# Override
|
16
|
+
def doi_registrar
|
17
|
+
'datacite'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Hyrax
|
3
|
+
module DOI
|
4
|
+
module DOIBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
DOI_REGEX = /\A10\.\d{4,}(\.\d+)*\/[-._;():\/A-Za-z\d]+\z/.freeze
|
8
|
+
|
9
|
+
included do
|
10
|
+
property :doi, predicate: ::RDF::Vocab::BIBO.doi, multiple: true do |index|
|
11
|
+
index.as :stored_sortable
|
12
|
+
end
|
13
|
+
|
14
|
+
validate :validate_doi
|
15
|
+
end
|
16
|
+
|
17
|
+
# Override this method
|
18
|
+
# Specify a registrar to use with this class
|
19
|
+
def doi_registrar
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Override this method
|
24
|
+
# Specify options for the registrar to use with this class
|
25
|
+
def doi_registrar_opts
|
26
|
+
{}
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_doi
|
32
|
+
Array(doi).each do |doi|
|
33
|
+
errors.add(:doi, "DOI (#{doi}) is invalid.") unless doi.match? DOI_REGEX
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|