orcid 0.0.1.pre → 0.0.1
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 +4 -4
- data/README.md +6 -2
- data/Rakefile +24 -9
- data/app/controllers/orcid/application_controller.rb +10 -0
- data/app/controllers/orcid/profile_connections_controller.rb +46 -0
- data/app/controllers/orcid/profile_requests_controller.rb +67 -0
- data/app/models/orcid/configuration.rb +19 -0
- data/app/models/orcid/profile.rb +44 -0
- data/app/models/orcid/profile_connection.rb +40 -0
- data/app/models/orcid/profile_request.rb +84 -0
- data/app/models/orcid/work.rb +90 -0
- data/app/services/orcid/profile_creation_service.rb +35 -0
- data/app/services/orcid/profile_lookup_service.rb +65 -0
- data/app/services/orcid/remote_work_service.rb +51 -0
- data/app/templates/orcid/work.template.v1.1.xml.erb +18 -0
- data/app/views/orcid/profile_connections/new.html.erb +17 -0
- data/app/views/orcid/profile_requests/new.html.erb +9 -0
- data/app/views/orcid/profile_requests/show.html.erb +5 -0
- data/config/locales/orcid.en.yml +28 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20140205185338_create_orcid_profile_requests.rb +12 -0
- data/lib/orcid.rb +69 -1
- data/lib/orcid/configuration.rb +20 -0
- data/lib/orcid/configuration/provider.rb +45 -0
- data/lib/orcid/engine.rb +14 -0
- data/lib/orcid/exceptions.rb +28 -0
- data/lib/orcid/spec_support.rb +54 -0
- data/lib/orcid/version.rb +1 -1
- metadata +261 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 148909130b9d10ade4c7e2e6b32d07321dcac06f
|
4
|
+
data.tar.gz: 0fb6c0784ef0a0000bda7e737fe7604519c7afe3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d8b914e980f40cb79f6d19942c56ba5f3a5d27330b05d3ef3cb3b3f2c809b829e5c566803b1b5ac1b5025a52da4163e1ee495c232142e2ee1a63fa69575d34c
|
7
|
+
data.tar.gz: 9bc94eba6a209de41c0fefa4719d511eb9528ff9c2fc02882bb3be065a0e80a1af06cef5d4afc7f2a23b77a731e76ce4460652536dd4eae7c9c2ebde71db0cd6
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -4,18 +4,33 @@ rescue LoadError
|
|
4
4
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
8
|
|
9
|
-
|
10
|
-
rdoc.rdoc_dir = 'rdoc'
|
11
|
-
rdoc.title = 'Orcid'
|
12
|
-
rdoc.options << '--line-numbers'
|
13
|
-
rdoc.rdoc_files.include('README.rdoc')
|
14
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
-
end
|
9
|
+
require 'engine_cart/rake_task'
|
16
10
|
|
11
|
+
require 'rspec/core/rake_task'
|
17
12
|
|
13
|
+
namespace :spec do
|
14
|
+
desc 'Only run specs that do not require net connect'
|
15
|
+
RSpec::Core::RakeTask.new(:offline) do |t|
|
16
|
+
t.rspec_opts = "--tag ~requires_net_connect"
|
17
|
+
end
|
18
18
|
|
19
|
+
desc 'Only run specs that require net connect'
|
20
|
+
RSpec::Core::RakeTask.new(:online) do |t|
|
21
|
+
t.rspec_opts = "--tag requires_net_connect"
|
22
|
+
end
|
19
23
|
|
20
|
-
|
24
|
+
desc 'Run the Travis CI specs'
|
25
|
+
task :travis do
|
26
|
+
ENV['RAILS_ENV'] = 'test'
|
27
|
+
ENV['SPEC_OPTS'] = "--profile 20"
|
28
|
+
Rake::Task['engine_cart:clean'].invoke
|
29
|
+
Rake::Task['engine_cart:generate'].invoke
|
30
|
+
Rake::Task['spec:offline'].invoke
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Rake::Task["default"].clear rescue nil
|
34
|
+
Rake::Task["spec"].clear
|
21
35
|
|
36
|
+
task :spec => 'spec:offline'
|
@@ -1,4 +1,14 @@
|
|
1
1
|
module Orcid
|
2
2
|
class ApplicationController < ActionController::Base
|
3
|
+
private
|
4
|
+
def redirecting_because_user_already_has_a_connected_orcid_profile
|
5
|
+
if orcid_profile = Orcid.profile_for(current_user)
|
6
|
+
flash[:notice] = I18n.t("orcid.requests.messages.previously_connected_profile", orcid_profile_id: orcid_profile.orcid_profile_id)
|
7
|
+
redirect_to main_app.root_path
|
8
|
+
return true
|
9
|
+
else
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
end
|
3
13
|
end
|
4
14
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Orcid
|
2
|
+
class ProfileConnectionsController < Orcid::ApplicationController
|
3
|
+
respond_to :html
|
4
|
+
before_filter :authenticate_user!
|
5
|
+
|
6
|
+
def index
|
7
|
+
render text: 'Not yet implemented!'
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
return false if redirecting_because_user_already_has_a_connected_orcid_profile
|
12
|
+
assign_attributes(new_profile_connection)
|
13
|
+
respond_with(new_profile_connection)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create
|
17
|
+
return false if redirecting_because_user_already_has_a_connected_orcid_profile
|
18
|
+
assign_attributes(new_profile_connection)
|
19
|
+
create_profile_connection(new_profile_connection)
|
20
|
+
respond_with(new_profile_connection)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
attr_reader :profile_connection
|
26
|
+
helper_method :profile_connection
|
27
|
+
|
28
|
+
def assign_attributes(profile_connection)
|
29
|
+
profile_connection.attributes = profile_connection_params
|
30
|
+
profile_connection.user = current_user
|
31
|
+
end
|
32
|
+
|
33
|
+
def profile_connection_params
|
34
|
+
params[:profile_connection] || {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_profile_connection(profile_connection)
|
38
|
+
profile_connection.save
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_profile_connection
|
42
|
+
@profile_connection ||= Orcid::ProfileConnection.new(params[:profile_connection])
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Orcid
|
2
|
+
class ProfileRequestsController < Orcid::ApplicationController
|
3
|
+
respond_to :html
|
4
|
+
before_filter :authenticate_user!
|
5
|
+
|
6
|
+
attr_reader :profile_request
|
7
|
+
helper_method :profile_request
|
8
|
+
|
9
|
+
def show
|
10
|
+
return false if redirecting_because_user_already_has_a_connected_orcid_profile
|
11
|
+
return false if redirecting_because_no_profile_request_was_found
|
12
|
+
respond_with(existing_profile_request)
|
13
|
+
end
|
14
|
+
|
15
|
+
def new
|
16
|
+
return false if redirecting_because_user_already_has_a_connected_orcid_profile
|
17
|
+
return false if redirecting_because_user_has_existing_profile_request
|
18
|
+
assign_attributes(new_profile_request)
|
19
|
+
respond_with(new_profile_request)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create
|
23
|
+
return false if redirecting_because_user_already_has_a_connected_orcid_profile
|
24
|
+
return false if redirecting_because_user_has_existing_profile_request
|
25
|
+
assign_attributes(new_profile_request)
|
26
|
+
create_profile_request(new_profile_request)
|
27
|
+
respond_with(new_profile_request)
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def redirecting_because_no_profile_request_was_found
|
33
|
+
return false if existing_profile_request
|
34
|
+
flash[:notice] = I18n.t("orcid.requests.messages.existing_request_not_found")
|
35
|
+
redirect_to new_profile_request_path
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def redirecting_because_user_has_existing_profile_request
|
40
|
+
return false if ! existing_profile_request
|
41
|
+
flash[:notice] = I18n.t("orcid.requests.messages.existing_request")
|
42
|
+
redirect_to profile_request_path
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def existing_profile_request
|
47
|
+
@profile_request ||= Orcid::ProfileRequest.find_by_user(current_user)
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_profile_request
|
51
|
+
@profile_request ||= Orcid::ProfileRequest.new(user: current_user)
|
52
|
+
end
|
53
|
+
|
54
|
+
def assign_attributes(profile_request)
|
55
|
+
profile_request.attributes = profile_request_params
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_profile_request(profile_request)
|
59
|
+
profile_request.save && Orcid.enqueue(profile_request)
|
60
|
+
end
|
61
|
+
|
62
|
+
def profile_request_params
|
63
|
+
return {} unless params.has_key?(:profile_request)
|
64
|
+
params[:profile_request].permit(:given_names, :family_name, :primary_email, :primary_email_confirmation)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Orcid
|
2
|
+
class Configuration
|
3
|
+
attr_reader :store
|
4
|
+
def initialize(store = ::ENV)
|
5
|
+
@store = store
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_writer :provider_name
|
9
|
+
def provider_name
|
10
|
+
@provider_name ||= 'orcid'
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_writer :authentication_model
|
14
|
+
def authentication_model
|
15
|
+
@authentication_model ||= Devise::MultiAuth::Authentication
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Orcid
|
2
|
+
class Profile
|
3
|
+
|
4
|
+
attr_reader :orcid_profile_id, :mapper, :remote_service, :xml_renderer, :xml_parser
|
5
|
+
private :mapper
|
6
|
+
def initialize(orcid_profile_id, config = {})
|
7
|
+
@orcid_profile_id = orcid_profile_id
|
8
|
+
@mapper = config.fetch(:mapper) { ::Mappy }
|
9
|
+
@remote_service = config.fetch(:remote_service) { Orcid::RemoteWorkService }
|
10
|
+
@xml_renderer = config.fetch(:xml_renderer) { Orcid::Work::XmlRenderer }
|
11
|
+
@xml_parser = config.fetch(:xml_parser) { Orcid::Work::XmlParser }
|
12
|
+
end
|
13
|
+
|
14
|
+
def remote_works(options = {})
|
15
|
+
@remote_works = nil if options.fetch(:force, false)
|
16
|
+
@remote_works ||= begin
|
17
|
+
response = remote_service.call(orcid_profile_id, request_method: :get)
|
18
|
+
xml_parser.call(response)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def append_new_work(*works)
|
23
|
+
orcid_works = normalize_work(*works)
|
24
|
+
xml = xml_renderer.call(orcid_works)
|
25
|
+
remote_service.call(orcid_profile_id, request_method: :post, body: xml)
|
26
|
+
end
|
27
|
+
|
28
|
+
def replace_works_with(*works)
|
29
|
+
orcid_works = normalize_work(*works)
|
30
|
+
xml = xml_renderer.call(orcid_works)
|
31
|
+
remote_service.call(orcid_profile_id, request_method: :put, body: xml)
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
# Note: We can handle
|
37
|
+
def normalize_work(*works)
|
38
|
+
Array(works).flatten.compact.collect do |work|
|
39
|
+
mapper.map(work, target: 'orcid/work')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Orcid
|
2
|
+
# Responsible for connecting an authenticated user to the ORCID profile that
|
3
|
+
# the user searched for and selected.
|
4
|
+
class ProfileConnection
|
5
|
+
include Virtus.model
|
6
|
+
include ActiveModel::Validations
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
attribute :email
|
9
|
+
attribute :orcid_profile_id
|
10
|
+
attribute :user
|
11
|
+
|
12
|
+
validates :user, presence: true
|
13
|
+
validates :orcid_profile_id, presence: true
|
14
|
+
|
15
|
+
def persisted?; false; end
|
16
|
+
|
17
|
+
def save(config = {})
|
18
|
+
persister = config.fetch(:persister) { Orcid.method(:connect_user_and_orcid_profile) }
|
19
|
+
valid? ? persister.call(user, orcid_profile_id) : false
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_orcid_profile_candidates
|
23
|
+
if query_for_orcid_profile_candidates?
|
24
|
+
yield(orcid_profile_candidates)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
attr_writer :orcid_profile_querier
|
28
|
+
protected
|
29
|
+
def orcid_profile_candidates
|
30
|
+
@orcid_profile_candidates ||= orcid_profile_querier.call({q: "email:#{email}"})
|
31
|
+
end
|
32
|
+
def query_for_orcid_profile_candidates?
|
33
|
+
email.present?
|
34
|
+
end
|
35
|
+
|
36
|
+
def orcid_profile_querier
|
37
|
+
@orcid_profile_querier ||= ProfileLookupService
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Orcid
|
2
|
+
# Responsible for:
|
3
|
+
# * acknowledging that an ORCID Profile was requested
|
4
|
+
# * submitting a request for an ORCID Profile
|
5
|
+
# * handling the response for the ORCID Profile creation
|
6
|
+
class ProfileRequest < ActiveRecord::Base
|
7
|
+
|
8
|
+
def self.find_by_user(user)
|
9
|
+
where(user: user).first
|
10
|
+
end
|
11
|
+
|
12
|
+
self.table_name = :orcid_profile_requests
|
13
|
+
|
14
|
+
validates :user_id, presence: true, uniqueness: true
|
15
|
+
validates :given_names, presence: true
|
16
|
+
validates :family_name, presence: true
|
17
|
+
validates :primary_email, presence: true, email: true, confirmation: true
|
18
|
+
|
19
|
+
belongs_to :user
|
20
|
+
|
21
|
+
def run(options = {})
|
22
|
+
# Why dependency injection? Because this is going to be a plugin, and things
|
23
|
+
# can't possibly be simple.
|
24
|
+
before_run_validator = options.fetch(:before_run_validator) { method(:validate_before_run) }
|
25
|
+
return false unless before_run_validator.call(self)
|
26
|
+
|
27
|
+
payload_xml_builder = options.fetch(:payload_xml_builder) { method(:xml_payload) }
|
28
|
+
profile_creation_service = options.fetch(:profile_creation_service) { Orcid::ProfileCreationService }
|
29
|
+
profile_creation_responder = options.fetch(:profile_creation_responder) { method(:handle_profile_creation_response) }
|
30
|
+
|
31
|
+
orcid_profile_id = profile_creation_service.call(payload_xml_builder.call(attributes))
|
32
|
+
profile_creation_responder.call(orcid_profile_id)
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_before_run(context = self)
|
36
|
+
|
37
|
+
if context.orcid_profile_id?
|
38
|
+
context.errors.add(:base, "#{context.class} ID=#{context.to_param} already has an assigned :orcid_profile_id #{context.orcid_profile_id.inspect}")
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
if user_orcid_profile = Orcid.profile_for(context.user)
|
43
|
+
context.errors.add(:base, "#{context.class} ID=#{context.to_param}'s associated user #{context.user.to_param} already has an assigned :orcid_profile_id #{user_orcid_profile.to_param}")
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
# NOTE: This one lies -> http://support.orcid.org/knowledgebase/articles/177522-create-an-id-technical-developer
|
51
|
+
# NOTE: This one was true at 2014-02-06:14:55 -> http://support.orcid.org/knowledgebase/articles/162412-tutorial-create-a-new-record-using-curl
|
52
|
+
def xml_payload(input = attributes)
|
53
|
+
attrs = input.with_indifferent_access
|
54
|
+
returning_value = <<-XML_TEMPLATE
|
55
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
56
|
+
<orcid-message
|
57
|
+
xmlns:xsi="http://www.orcid.org/ns/orcid https://raw.github.com/ORCID/ORCID-Source/master/orcid-model/src/main/resources/orcid-message-1.1.xsd"
|
58
|
+
xmlns="http://www.orcid.org/ns/orcid">
|
59
|
+
<message-version>1.1</message-version>
|
60
|
+
<orcid-profile>
|
61
|
+
<orcid-bio>
|
62
|
+
<personal-details>
|
63
|
+
<given-names>#{attrs.fetch('given_names')}</given-names>
|
64
|
+
<family-name>#{attrs.fetch('family_name')}</family-name>
|
65
|
+
</personal-details>
|
66
|
+
<contact-details>
|
67
|
+
<email primary="true">#{attrs.fetch('primary_email')}</email>
|
68
|
+
</contact-details>
|
69
|
+
</orcid-bio>
|
70
|
+
</orcid-profile>
|
71
|
+
</orcid-message>
|
72
|
+
XML_TEMPLATE
|
73
|
+
returning_value.strip
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle_profile_creation_response(orcid_profile_id)
|
77
|
+
self.class.transaction do
|
78
|
+
update_column(:orcid_profile_id, orcid_profile_id)
|
79
|
+
Orcid.connect_user_and_orcid_profile(user, orcid_profile_id)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Orcid
|
2
|
+
# A well-defined data structure that coordinates with its :template in order
|
3
|
+
# to generate XML that can be POSTed/PUT as an Orcid Work.
|
4
|
+
class Work
|
5
|
+
VALID_WORK_TYPES = [
|
6
|
+
"artistic-performance","book-chapter","book-review","book","conference-abstract","conference-paper","conference-poster","data-set","dictionary-entry","disclosure","dissertation","edited-book","encyclopedia-entry","invention","journal-article","journal-issue","lecture-speech","license","magazine-article","manual","newsletter-article","newspaper-article","online-resource","other","patent","registered-copyright","report","research-technique","research-tool","spin-off-company","standards-and-policy","supervised-student-publication","technical-standard","test","translation","trademark","website","working-paper",
|
7
|
+
].freeze
|
8
|
+
|
9
|
+
include Virtus.model
|
10
|
+
include ActiveModel::Validations
|
11
|
+
extend ActiveModel::Naming
|
12
|
+
|
13
|
+
attribute :title, String
|
14
|
+
validates :title, presence: true
|
15
|
+
|
16
|
+
attribute :work_type, String
|
17
|
+
validates :work_type, presence: true, inclusion: { in: VALID_WORK_TYPES }
|
18
|
+
|
19
|
+
attribute :put_code, String
|
20
|
+
|
21
|
+
def to_xml
|
22
|
+
XmlRenderer.call(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ==(comparison_object)
|
26
|
+
super || comparison_object.instance_of?(self.class) &&
|
27
|
+
id.present? &&
|
28
|
+
comparison_object.id == id
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
if put_code.present?
|
33
|
+
put_code
|
34
|
+
elsif title.present? && work_type.present?
|
35
|
+
[title, work_type]
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class XmlRenderer
|
42
|
+
def self.call(works, options = {})
|
43
|
+
new(works, options).call
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :works, :template
|
47
|
+
def initialize(works, options = {})
|
48
|
+
self.works = works
|
49
|
+
@template = options.fetch(:template_path) { Orcid::Engine.root.join('app/templates/orcid/work.template.v1.1.xml.erb').read }
|
50
|
+
end
|
51
|
+
|
52
|
+
def call
|
53
|
+
ERB.new(template).result(binding)
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
def works=(thing)
|
58
|
+
@works = Array(thing)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
class XmlParser
|
64
|
+
def self.call(xml)
|
65
|
+
new(xml).call
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :xml
|
69
|
+
def initialize(xml)
|
70
|
+
@xml = xml
|
71
|
+
end
|
72
|
+
|
73
|
+
def call
|
74
|
+
document = Nokogiri::XML.parse(xml)
|
75
|
+
document.css('orcid-works orcid-work').collect do |node|
|
76
|
+
transform(node)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def transform(node)
|
82
|
+
Orcid::Work.new.tap do |work|
|
83
|
+
work.put_code = node.attributes.fetch("put-code").value
|
84
|
+
work.title = node.css('work-title title').text
|
85
|
+
work.work_type = node.css('work-type').text
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Responsible for minting a new ORCID for the given payload.
|
2
|
+
module Orcid
|
3
|
+
class ProfileCreationService
|
4
|
+
|
5
|
+
def self.call(payload, config = {})
|
6
|
+
new(config).call(payload)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :token, :path, :headers
|
10
|
+
def initialize(config = {})
|
11
|
+
@token = config.fetch(:token) { Orcid.client_credentials_token('/orcid-profile/create') }
|
12
|
+
@path = config.fetch(:path) { "v1.1/orcid-profile" }
|
13
|
+
@headers = config.fetch(:headers) { default_headers }
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(payload)
|
17
|
+
response = deliver(payload)
|
18
|
+
parse(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
def deliver(body)
|
23
|
+
token.post(path, body: body, headers: headers)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(response)
|
27
|
+
uri = URI.parse(response.headers.fetch(:location))
|
28
|
+
uri.path.sub(/\A\//, "").split("/").first
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_headers
|
32
|
+
{ "Accept" => 'application/xml', 'Content-Type'=>'application/vdn.orcid+xml' }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Orcid
|
2
|
+
class ProfileLookupService
|
3
|
+
class SearchResponse
|
4
|
+
delegate :fetch, :has_key?, :[], to: :@attributes
|
5
|
+
def initialize(attributes = {})
|
6
|
+
@attributes = attributes.with_indifferent_access
|
7
|
+
end
|
8
|
+
def id
|
9
|
+
@attributes.fetch(:id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def label
|
13
|
+
@attributes.fetch(:label)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.call(query, config = {})
|
18
|
+
new(config).call(query)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :token, :path, :headers, :response_builder
|
22
|
+
def initialize(config = {})
|
23
|
+
@token = config.fetch(:token) { Orcid.client_credentials_token('/read-public') }
|
24
|
+
@response_builder = config.fetch(:response_builder) { SearchResponse }
|
25
|
+
@path = config.fetch(:path) { "v1.1/search/orcid-bio/" }
|
26
|
+
@headers = config.fetch(:headers) {
|
27
|
+
{
|
28
|
+
:accept => 'application/orcid+json',
|
29
|
+
'Content-Type'=>'application/orcid+xml'
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(parameters)
|
35
|
+
response = deliver(parameters)
|
36
|
+
parse(response.body)
|
37
|
+
end
|
38
|
+
alias_method :search, :call
|
39
|
+
|
40
|
+
protected
|
41
|
+
attr_reader :host, :access_token
|
42
|
+
def deliver(parameters)
|
43
|
+
token.get(path, headers: headers, params: parameters)
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse(document)
|
47
|
+
json = JSON.parse(document)
|
48
|
+
|
49
|
+
json.fetch('orcid-search-results').fetch('orcid-search-result').each_with_object([]) do |result, returning_value|
|
50
|
+
profile = result.fetch('orcid-profile')
|
51
|
+
identifier = profile.fetch('orcid-identifier').fetch('path')
|
52
|
+
orcid_bio = profile.fetch('orcid-bio')
|
53
|
+
given_names = orcid_bio.fetch('personal-details').fetch('given-names').fetch('value')
|
54
|
+
family_name = orcid_bio.fetch('personal-details').fetch('family-name').fetch('value')
|
55
|
+
emails = orcid_bio.fetch('contact-details').fetch('email').collect {|email| email.fetch('value') }
|
56
|
+
label = "#{given_names} #{family_name}"
|
57
|
+
label << " (" << emails.join(",") << ")" if emails.present?
|
58
|
+
label << " [ORCID: #{identifier}]"
|
59
|
+
|
60
|
+
returning_value << response_builder.new("id" => identifier, "label" => label)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Orcid
|
2
|
+
class RemoteWorkService
|
3
|
+
def self.call(orcid_profile_id, options = {})
|
4
|
+
new(orcid_profile_id, options).call
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :headers, :token, :orcid_profile_id, :body, :request_method, :path
|
8
|
+
def initialize(orcid_profile_id, options = {})
|
9
|
+
@orcid_profile_id = orcid_profile_id
|
10
|
+
@request_method = options.fetch(:request_method) { :get }
|
11
|
+
@body = options.fetch(:body) { "" }
|
12
|
+
@token = options.fetch(:token) { Orcid.access_token_for(orcid_profile_id) }
|
13
|
+
@headers = options.fetch(:headers) { default_headers }
|
14
|
+
@path = options.fetch(:path) { default_path }
|
15
|
+
end
|
16
|
+
|
17
|
+
# :post will append works to the Orcid Profile
|
18
|
+
# :put will replace the existing Orcid Profile works with the payload
|
19
|
+
# :get will retrieve the Orcid Profile
|
20
|
+
# http://support.orcid.org/knowledgebase/articles/177528-add-works-technical-developer
|
21
|
+
def call
|
22
|
+
response = deliver
|
23
|
+
response.body
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
def deliver
|
28
|
+
token.request(request_method, path, body: body, headers: headers)
|
29
|
+
rescue OAuth2::Error => e
|
30
|
+
raise RemoteServiceError.new(
|
31
|
+
response_body: e.response.body,
|
32
|
+
response_status: e.response.status,
|
33
|
+
client: token.client,
|
34
|
+
token: token,
|
35
|
+
request_method: request_method,
|
36
|
+
request_path: path,
|
37
|
+
request_body: body,
|
38
|
+
request_headers: headers
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_headers
|
43
|
+
{ 'Accept' => 'application/xml', 'Content-Type'=>'application/orcid+xml' }
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_path
|
47
|
+
"v1.1/#{orcid_profile_id}/orcid-works/"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<orcid-message xmlns="http://www.orcid.org/ns/orcid"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xsi:schemaLocation="https://raw.github.com/ORCID/ORCID-Source/master/orcid-model/src/main/resources/orcid-message-1.1.xsd">
|
5
|
+
<message-version>1.1</message-version>
|
6
|
+
<orcid-profile>
|
7
|
+
<orcid-activities>
|
8
|
+
<orcid-works><% works.each do |work| %>
|
9
|
+
<orcid-work>
|
10
|
+
<work-title>
|
11
|
+
<title><%= work.title %></title>
|
12
|
+
</work-title>
|
13
|
+
<work-type><%= work.work_type %></work-type>
|
14
|
+
</orcid-work>
|
15
|
+
<% end %></orcid-works>
|
16
|
+
</orcid-activities>
|
17
|
+
</orcid-profile>
|
18
|
+
</orcid-message>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= simple_form_for(profile_connection, as: :profile_connection, url: orcid.new_profile_connection_path, method: :get, html: {class: 'search-form'}) do |f| %>
|
2
|
+
<%= field_set_tag("Search ORCID Profiles", class: 'accessible-hidden') do %>
|
3
|
+
<%= f.input :email, type: :search %>
|
4
|
+
<% end %>
|
5
|
+
<button type="submit" class="search-submit btn btn-primary" id="keyword-search-submit" tabindex="2">
|
6
|
+
<i class="icon-search icon-white"></i><span class="accessible-hidden">Search</span>
|
7
|
+
</button>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<% profile_connection.with_orcid_profile_candidates do |candidates| %>
|
11
|
+
<%= simple_form_for(profile_connection, as: :profile_connection, url: orcid.profile_connections_path,) do |f| %>
|
12
|
+
<%= field_set_tag("Select an ORCID Profile", class: 'accessible-hidden') do %>
|
13
|
+
<%= f.collection_radio_buttons :orcid_profile_id, candidates, :id, :label %>
|
14
|
+
<% end %>
|
15
|
+
<%= f.submit %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%= simple_form_for profile_request, as: :profile_request, url: orcid.profile_request_path do |f| %>
|
2
|
+
<%= field_set_tag do%>
|
3
|
+
<%= f.input :given_names %>
|
4
|
+
<%= f.input :family_name %>
|
5
|
+
<%= f.input :primary_email %>
|
6
|
+
<%= f.input :primary_email_confirmation %>
|
7
|
+
<% end %>
|
8
|
+
<%= f.submit %>
|
9
|
+
<% end %>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<p><strong>Requestor:</strong> <%= profile_request.user %></p>
|
2
|
+
<p><strong>Given names:</strong> <%= profile_request.given_names %></p>
|
3
|
+
<p><strong>Family name:</strong> <%= profile_request.family_name %></p>
|
4
|
+
<p><strong>Primary email:</strong> <%= profile_request.primary_email %></p>
|
5
|
+
<p><strong>ORCID Profile ID:</strong> <%= profile_request.orcid_profile_id %></p>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Files in the config/locales directory are used for internationalization
|
2
|
+
# and are automatically loaded by Rails. If you want to use locales other
|
3
|
+
# than English, add the necessary files in this directory.
|
4
|
+
#
|
5
|
+
# To use the locales, use `I18n.t`:
|
6
|
+
#
|
7
|
+
# I18n.t 'hello'
|
8
|
+
#
|
9
|
+
# In views, this is aliased to just `t`:
|
10
|
+
#
|
11
|
+
# <%= t('hello') %>
|
12
|
+
#
|
13
|
+
# To use a different locale, set it with `I18n.locale`:
|
14
|
+
#
|
15
|
+
# I18n.locale = :es
|
16
|
+
#
|
17
|
+
# This would use the information in config/locales/es.yml.
|
18
|
+
#
|
19
|
+
# To learn more, please read the Rails Internationalization guide
|
20
|
+
# available at http://guides.rubyonrails.org/i18n.html.
|
21
|
+
|
22
|
+
en:
|
23
|
+
orcid:
|
24
|
+
requests:
|
25
|
+
messages:
|
26
|
+
existing_request_not_found: "Unable to find an existing Orcid Profile request. Go ahead and create one."
|
27
|
+
existing_request: "You have already submitted an Orcid Profile request."
|
28
|
+
previously_connected_profile: "You have already connected to an Orcid Profile (%{orcid_profile_id})."
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateOrcidProfileRequests < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :orcid_profile_requests do |t|
|
4
|
+
t.integer :user_id, unique: true, index: true, null: false
|
5
|
+
t.string :given_names, null: false
|
6
|
+
t.string :family_name, null: false
|
7
|
+
t.string :primary_email, null: false
|
8
|
+
t.string :orcid_profile_id, unique: true, index: true
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/orcid.rb
CHANGED
@@ -1,4 +1,72 @@
|
|
1
|
-
require
|
1
|
+
require 'orcid/engine'
|
2
|
+
require 'orcid/configuration'
|
3
|
+
require 'orcid/exceptions'
|
4
|
+
|
5
|
+
require 'mappy'
|
6
|
+
require 'devise_multi_auth'
|
7
|
+
require 'virtus'
|
8
|
+
require 'omniauth-orcid'
|
9
|
+
require 'email_validator'
|
10
|
+
require 'simple_form'
|
2
11
|
|
3
12
|
module Orcid
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
module_function
|
19
|
+
def configure
|
20
|
+
self.configuration ||= Configuration.new
|
21
|
+
yield(configuration)
|
22
|
+
end
|
23
|
+
|
24
|
+
def provider
|
25
|
+
@provider ||= Configuration::Provider.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def provider_name
|
29
|
+
configuration.provider_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def authentication_model
|
33
|
+
configuration.authentication_model
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def connect_user_and_orcid_profile(user, orcid_profile_id, options = {})
|
38
|
+
authentication_model.create!(provider: provider_name, uid: orcid_profile_id, user: user)
|
39
|
+
end
|
40
|
+
|
41
|
+
def access_token_for(orcid_profile_id, options = {})
|
42
|
+
client = options.fetch(:client) { oauth_client }
|
43
|
+
tokenizer = options.fetch(:tokenizer) { authentication_model }
|
44
|
+
tokenizer.to_access_token(uid: orcid_profile_id, provider: provider_name, client: client)
|
45
|
+
end
|
46
|
+
|
47
|
+
def profile_for(user)
|
48
|
+
if auth = authentication_model.where(provider: provider_name, user: user).first
|
49
|
+
Orcid::Profile.new(auth.uid)
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def enqueue(object)
|
56
|
+
object.run
|
57
|
+
end
|
58
|
+
|
59
|
+
def oauth_client
|
60
|
+
# passing the site: option as Orcid's Sandbox has an invalid certificate
|
61
|
+
# for the api.sandbox-1.orcid.org
|
62
|
+
@oauth_client ||= Devise::MultiAuth.oauth_client_for(
|
63
|
+
provider_name, options: { site: provider.site_url }
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def client_credentials_token(scope, options = {})
|
68
|
+
tokenizer = options.fetch(:tokenizer) { oauth_client.client_credentials }
|
69
|
+
tokenizer.get_token(scope: scope)
|
70
|
+
end
|
71
|
+
|
4
72
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Orcid
|
2
|
+
class Configuration
|
3
|
+
attr_reader :store
|
4
|
+
def initialize(store = ::ENV)
|
5
|
+
@store = store
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_writer :provider_name
|
9
|
+
def provider_name
|
10
|
+
@provider_name ||= 'orcid'
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_writer :authentication_model
|
14
|
+
def authentication_model
|
15
|
+
@authentication_model ||= Devise::MultiAuth::Authentication
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
require 'orcid/configuration/provider'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Orcid
|
2
|
+
class Configuration::Provider
|
3
|
+
attr_reader :store
|
4
|
+
def initialize(store = ::ENV)
|
5
|
+
@store = store
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_writer :authentication_scope
|
9
|
+
def authentication_scope
|
10
|
+
@authentication_scope ||= store.fetch('ORCID_APP_AUTHENTICATION_SCOPE') {
|
11
|
+
"/authenticate,/orcid-works/create,/orcid-works/update,/read-public,/orcid-grants/create"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_writer :site_url
|
16
|
+
def site_url
|
17
|
+
@site_url ||= store.fetch('ORCID_SITE_URL') { "http://api.sandbox-1.orcid.org" }
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_writer :token_url
|
21
|
+
def token_url
|
22
|
+
@token_url ||= store.fetch('ORCID_TOKEN_URL') { "https://api.sandbox-1.orcid.org/oauth/token" }
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_writer :signin_via_json_url
|
26
|
+
def signin_via_json_url
|
27
|
+
@signin_via_json_url ||= store.fetch('ORCID_REMOTE_SIGNIN_URL') { "https://sandbox-1.orcid.org/signin/auth.json" }
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_writer :authorize_url
|
31
|
+
def authorize_url
|
32
|
+
@authorize_url ||= store.fetch('ORCID_AUTHORIZE_URL') { "https://sandbox-1.orcid.org/oauth/authorize" }
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_writer :id
|
36
|
+
def id
|
37
|
+
@id ||= store.fetch('ORCID_APP_ID')
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_writer :secret
|
41
|
+
def secret
|
42
|
+
@secret ||= store.fetch('ORCID_APP_SECRET')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/orcid/engine.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
module Orcid
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Orcid
|
4
|
+
|
5
|
+
initializer 'orcid.initializers' do |app|
|
6
|
+
app.config.paths.add 'app/services', eager_load: true
|
7
|
+
app.config.autoload_paths += %W(
|
8
|
+
#{config.root}/app/services
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
config.before_initialize do |app|
|
13
|
+
Orcid.configure do |config|
|
14
|
+
config.provider_name = 'orcid'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
4
18
|
end
|
5
19
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Orcid
|
2
|
+
# Because in trouble shooting what all goes into this remote call,
|
3
|
+
# you may very well want all of this.
|
4
|
+
class RemoteServiceError < RuntimeError
|
5
|
+
def initialize(options)
|
6
|
+
text = []
|
7
|
+
text << "-- Client --"
|
8
|
+
if client = options[:client]
|
9
|
+
text << "id:\n\t#{client.id.inspect}"
|
10
|
+
text << "site:\n\t#{client.site.inspect}"
|
11
|
+
text << "options:\n\t#{client.options.inspect}"
|
12
|
+
end
|
13
|
+
text << "\n-- Token --"
|
14
|
+
if token = options[:token]
|
15
|
+
text << "access_token:\n\t#{token.token.inspect}"
|
16
|
+
text << "refresh_token:\n\t#{token.refresh_token.inspect}"
|
17
|
+
end
|
18
|
+
text << "\n-- Request --"
|
19
|
+
text << "path:\n\t#{options[:request_path].inspect}" if options[:request_path]
|
20
|
+
text << "headers:\n\t#{options[:request_headers].inspect}" if options[:request_headers]
|
21
|
+
text << "body:\n\t#{options[:request_body]}" if options[:request_body]
|
22
|
+
text << "\n-- Response --"
|
23
|
+
text << "status:\n\t#{options[:response_status].inspect}" if options[:response_status]
|
24
|
+
text << "body:\n\t#{options[:response_body]}" if options[:response_body]
|
25
|
+
super(text.join("\n"))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
class RequestSandboxAuthorizationCode
|
3
|
+
|
4
|
+
def self.call(options = {}, config = {})
|
5
|
+
new(config).call(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :cookies, :access_scope, :authorize_url, :login_url
|
9
|
+
attr_reader :oauth_redirect_uri, :orcid_client_id, :authorization_code, :orcid_client_secret
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@orcid_client_id = options.fetch(:orcid_client_id) { Orcid.provider.id }
|
13
|
+
@orcid_client_secret = options.fetch(:orcid_client_secret) { Orcid.provider.secret }
|
14
|
+
@login_url = options.fetch(:login_url) { Orcid.provider.signin_via_json_url }
|
15
|
+
@authorize_url = options.fetch(:authorize_url) { Orcid.provider.authorize_url }
|
16
|
+
@oauth_redirect_uri = options.fetch(:oauth_redirect_uri) { 'https://developers.google.com/oauthplayground' }
|
17
|
+
@access_scope = options.fetch(:scope) { Orcid.provider.authentication_scope }
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(options = {})
|
21
|
+
orcid_profile_id = options.fetch(:orcid_profile_id) { ENV['ORCID_CLAIMED_PROFILE_ID'] }
|
22
|
+
password = options.fetch(:password) { ENV['ORCID_CLAIMED_PROFILE_PASSWORD']}
|
23
|
+
|
24
|
+
login_to_orcid(orcid_profile_id, password)
|
25
|
+
request_authorization
|
26
|
+
request_authorization_code
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_writer :cookies
|
30
|
+
private :cookies
|
31
|
+
|
32
|
+
private
|
33
|
+
def login_to_orcid(orcid_profile_id, password)
|
34
|
+
response = RestClient.post(login_url, userId: orcid_profile_id, password: password )
|
35
|
+
if ! JSON.parse(response)["success"]
|
36
|
+
raise "Response not successful: \n#{response}"
|
37
|
+
else
|
38
|
+
self.cookies = response.cookies
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def request_authorization
|
43
|
+
parameters = { client_id: orcid_client_id, response_type: 'code', scope: access_scope, redirect_uri: oauth_redirect_uri }
|
44
|
+
RestClient.get(authorize_url, {params: parameters, cookies: cookies})
|
45
|
+
end
|
46
|
+
|
47
|
+
def request_authorization_code
|
48
|
+
RestClient.post(authorize_url, {user_oauth_approval: true}, {cookies: cookies})
|
49
|
+
rescue RestClient::Found => e
|
50
|
+
uri = URI.parse(e.response.headers.fetch(:location))
|
51
|
+
CGI::parse(uri.query).fetch('code').first
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/orcid/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orcid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Friesen
|
@@ -24,6 +24,104 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 4.0.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mappy
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: devise-multi_auth
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.0.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.0.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: omniauth-orcid
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: virtus
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: email_validator
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simple_form
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
27
125
|
- !ruby/object:Gem::Dependency
|
28
126
|
name: sqlite3
|
29
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +136,146 @@ dependencies:
|
|
38
136
|
- - '>='
|
39
137
|
- !ruby/object:Gem::Version
|
40
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: engine_cart
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rspec-rails
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: database_cleaner
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: factory_girl
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rspec-html-matchers
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - '>='
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - '>='
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: capybara
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - '>='
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - '>='
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: capybara-webkit
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - '>='
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - '>='
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: webmock
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - '>='
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '0'
|
244
|
+
type: :development
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - '>='
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: figaro
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - '>='
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - '>='
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
265
|
+
- !ruby/object:Gem::Dependency
|
266
|
+
name: rest_client
|
267
|
+
requirement: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - '>='
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '0'
|
272
|
+
type: :development
|
273
|
+
prerelease: false
|
274
|
+
version_requirements: !ruby/object:Gem::Requirement
|
275
|
+
requirements:
|
276
|
+
- - '>='
|
277
|
+
- !ruby/object:Gem::Version
|
278
|
+
version: '0'
|
41
279
|
description: A Rails engine for orcid.org integration.
|
42
280
|
email:
|
43
281
|
- jeremy.n.friesen@gmail.com
|
@@ -48,10 +286,30 @@ files:
|
|
48
286
|
- app/assets/javascripts/orcid/application.js
|
49
287
|
- app/assets/stylesheets/orcid/application.css
|
50
288
|
- app/controllers/orcid/application_controller.rb
|
289
|
+
- app/controllers/orcid/profile_connections_controller.rb
|
290
|
+
- app/controllers/orcid/profile_requests_controller.rb
|
51
291
|
- app/helpers/orcid/application_helper.rb
|
292
|
+
- app/models/orcid/configuration.rb
|
293
|
+
- app/models/orcid/profile.rb
|
294
|
+
- app/models/orcid/profile_connection.rb
|
295
|
+
- app/models/orcid/profile_request.rb
|
296
|
+
- app/models/orcid/work.rb
|
297
|
+
- app/services/orcid/profile_creation_service.rb
|
298
|
+
- app/services/orcid/profile_lookup_service.rb
|
299
|
+
- app/services/orcid/remote_work_service.rb
|
300
|
+
- app/templates/orcid/work.template.v1.1.xml.erb
|
52
301
|
- app/views/layouts/orcid/application.html.erb
|
302
|
+
- app/views/orcid/profile_connections/new.html.erb
|
303
|
+
- app/views/orcid/profile_requests/new.html.erb
|
304
|
+
- app/views/orcid/profile_requests/show.html.erb
|
305
|
+
- config/locales/orcid.en.yml
|
53
306
|
- config/routes.rb
|
307
|
+
- db/migrate/20140205185338_create_orcid_profile_requests.rb
|
308
|
+
- lib/orcid/configuration/provider.rb
|
309
|
+
- lib/orcid/configuration.rb
|
54
310
|
- lib/orcid/engine.rb
|
311
|
+
- lib/orcid/exceptions.rb
|
312
|
+
- lib/orcid/spec_support.rb
|
55
313
|
- lib/orcid/version.rb
|
56
314
|
- lib/orcid.rb
|
57
315
|
- lib/tasks/orcid_tasks.rake
|
@@ -72,9 +330,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
330
|
version: '0'
|
73
331
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
332
|
requirements:
|
75
|
-
- - '
|
333
|
+
- - '>='
|
76
334
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
335
|
+
version: '0'
|
78
336
|
requirements: []
|
79
337
|
rubyforge_project:
|
80
338
|
rubygems_version: 2.0.14
|