orcid 0.8.0 → 0.8.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +0 -0
  3. data/.hound.yml +10 -0
  4. data/.mailmap +3 -0
  5. data/.travis.yml +1 -1
  6. data/Gemfile +1 -0
  7. data/README.md +39 -2
  8. data/app/controllers/orcid/profile_connections_controller.rb +4 -0
  9. data/app/controllers/orcid/profile_requests_controller.rb +5 -1
  10. data/app/models/orcid/profile.rb +26 -11
  11. data/app/models/orcid/profile_connection.rb +14 -4
  12. data/app/models/orcid/profile_request.rb +6 -80
  13. data/app/models/orcid/profile_status.rb +7 -1
  14. data/app/models/orcid/work/xml_renderer.rb +6 -4
  15. data/app/services/orcid/profile_request_coordinator.rb +112 -0
  16. data/app/services/orcid/remote/profile_creation_service.rb +6 -7
  17. data/app/services/orcid/remote/profile_query_service.rb +2 -5
  18. data/app/services/orcid/remote/profile_query_service/response_parser.rb +13 -7
  19. data/db/migrate/20140205185339_update_orcid_profile_requests.rb +6 -0
  20. data/lib/orcid.rb +15 -1
  21. data/lib/orcid/engine.rb +0 -15
  22. data/lib/orcid/exceptions.rb +24 -2
  23. data/lib/orcid/version.rb +1 -1
  24. data/orcid.gemspec +5 -1
  25. data/spec/controllers/orcid/profile_requests_controller_spec.rb +2 -2
  26. data/spec/features/non_ui_based_interactions_spec.rb +3 -1
  27. data/spec/features/orcid_work_query_spec.rb +17 -0
  28. data/spec/lib/orcid/exceptions_spec.rb +33 -0
  29. data/spec/lib/orcid_spec.rb +1 -0
  30. data/spec/models/orcid/profile_connection_spec.rb +8 -6
  31. data/spec/models/orcid/profile_request_spec.rb +9 -91
  32. data/spec/models/orcid/work_spec.rb +21 -0
  33. data/spec/services/orcid/profile_request_coordinator_spec.rb +111 -0
  34. data/spec/services/orcid/remote/profile_creation_service_spec.rb +17 -0
  35. data/spec/services/orcid/remote/profile_query_service/query_parameter_builder_spec.rb +11 -16
  36. data/spec/services/orcid/remote/profile_query_service_spec.rb +21 -9
  37. data/spec/services/orcid/remote/service_spec.rb +9 -4
  38. data/spec/spec_helper.rb +4 -0
  39. metadata +16 -5
  40. data/rubocop.txt +0 -1164
@@ -12,9 +12,7 @@ module Orcid
12
12
  attr_reader :token, :path, :headers
13
13
  def initialize(config = {}, &callback_config)
14
14
  super(&callback_config)
15
- @token = config.fetch(:token) do
16
- Orcid.client_credentials_token('/orcid-profile/create')
17
- end
15
+ @token = config.fetch(:token) { default_token }
18
16
  @path = config.fetch(:path) { 'v1.1/orcid-profile' }
19
17
  @headers = config.fetch(:headers) { default_headers }
20
18
  end
@@ -56,10 +54,11 @@ module Orcid
56
54
  end
57
55
 
58
56
  def default_headers
59
- {
60
- 'Accept' => 'application/xml',
61
- 'Content-Type' => 'application/vdn.orcid+xml'
62
- }
57
+ { 'Accept' => 'application/xml', 'Content-Type' => 'application/vdn.orcid+xml' }
58
+ end
59
+
60
+ def default_token
61
+ Orcid.client_credentials_token('/orcid-profile/create')
63
62
  end
64
63
  end
65
64
  end
@@ -35,14 +35,11 @@ module Orcid
35
35
  end
36
36
 
37
37
  def default_headers
38
- {
39
- :accept => 'application/orcid+json',
40
- 'Content-Type' => 'application/orcid+xml'
41
- }
38
+ { :accept => 'application/orcid+json', 'Content-Type' => 'application/orcid+xml' }
42
39
  end
43
40
 
44
41
  def issue_callbacks(search_results)
45
- if Array(search_results).flatten.compact.any?
42
+ if Array.wrap(search_results).any?(&:present?)
46
43
  callback(:found, search_results)
47
44
  else
48
45
  callback(:not_found)
@@ -2,6 +2,7 @@ require_dependency 'orcid/remote/profile_query_service'
2
2
  module Orcid
3
3
  module Remote
4
4
  class ProfileQueryService
5
+ # Responsible for parsing a response document
5
6
  class ResponseParser
6
7
 
7
8
  # A convenience method to expose entry into the ResponseParser function
@@ -10,14 +11,10 @@ module Orcid
10
11
  end
11
12
 
12
13
  attr_reader :response_builder, :logger
13
-
14
+ private :response_builder, :logger
14
15
  def initialize(collaborators = {})
15
- @response_builder = collaborators.fetch(:response_builder) do
16
- SearchResponse
17
- end
18
- @logger = collaborators.fetch(:logger) do
19
- Rails.logger
20
- end
16
+ @response_builder = collaborators.fetch(:response_builder) { default_response_builder }
17
+ @logger = collaborators.fetch(:logger) { default_logger }
21
18
  end
22
19
 
23
20
  def call(document)
@@ -47,6 +44,15 @@ module Orcid
47
44
  returning_value
48
45
  end
49
46
  end
47
+
48
+ private
49
+ def default_logger
50
+ Rails.logger
51
+ end
52
+
53
+ def default_response_builder
54
+ SearchResponse
55
+ end
50
56
  end
51
57
  end
52
58
  end
@@ -0,0 +1,6 @@
1
+ class UpdateOrcidProfileRequests < ActiveRecord::Migration
2
+ def change
3
+ add_column :orcid_profile_requests, :response_text, :text
4
+ add_column :orcid_profile_requests, :response_status, :string, index: true
5
+ end
6
+ end
data/lib/orcid.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'orcid/engine'
1
+ require 'orcid/engine' if defined?(Rails)
2
2
  require 'orcid/configuration'
3
3
  require 'orcid/exceptions'
4
4
  require 'figaro'
@@ -87,4 +87,18 @@ module Orcid
87
87
  tokenizer = options.fetch(:tokenizer) { oauth_client.client_credentials }
88
88
  tokenizer.get_token(scope: scope)
89
89
  end
90
+
91
+ # As per an isolated_namespace Rails engine.
92
+ # But the isolated namespace creates issues.
93
+ # @api private
94
+ def table_name_prefix
95
+ 'orcid_'
96
+ end
97
+
98
+ # Because I am not using isolate_namespace for Orcid::Engine
99
+ # I need this for the application router to find the appropriate routes.
100
+ # @api private
101
+ def use_relative_model_naming?
102
+ true
103
+ end
90
104
  end
data/lib/orcid/engine.rb CHANGED
@@ -1,20 +1,5 @@
1
1
  # The namespace for all things related to Orcid integration
2
2
  module Orcid
3
- module_function
4
-
5
- # As per an isolated_namespace Rails engine.
6
- # But the isolated namespace creates issues.
7
- # @api private
8
- def table_name_prefix
9
- 'orcid_'
10
- end
11
-
12
- # Because I am not using isolate_namespace for Orcid::Engine
13
- # I need this for the application router to find the appropriate routes.
14
- # @api private
15
- def use_relative_model_naming?
16
- true
17
- end
18
3
 
19
4
  # While not an isolated namespace engine
20
5
  # @See http://guides.rubyonrails.org/engines.html
@@ -1,6 +1,28 @@
1
1
  module Orcid
2
2
 
3
- class ConfigurationError < RuntimeError
3
+ # Intended to be the base for all exceptions raised by the Orcid gem.
4
+ class BaseError < RuntimeError
5
+ end
6
+
7
+ class ProfileRequestStateError < BaseError
8
+ def initialize(user)
9
+ super("Unexpected Orcid::ProfileRequest state for #{user.class} ID=#{user.to_param}.")
10
+ end
11
+ end
12
+
13
+ class ProfileRequestMethodExpectedError < BaseError
14
+ def initialize(request, method_name)
15
+ super("Expected #{request.inspect} to respond to :#{method_name}.")
16
+ end
17
+ end
18
+
19
+ class MissingUserForProfileRequest < BaseError
20
+ def initialize(request)
21
+ super("#{request.class} ID=#{request.to_param} is not associated with a :user.")
22
+ end
23
+ end
24
+
25
+ class ConfigurationError < BaseError
4
26
  def initialize(key_name)
5
27
  super("Unable to find #{key_name.inspect} in configuration storage.")
6
28
  end
@@ -8,7 +30,7 @@ module Orcid
8
30
 
9
31
  # Because in trouble shooting what all goes into this remote call,
10
32
  # you may very well want all of this.
11
- class RemoteServiceError < RuntimeError
33
+ class RemoteServiceError < BaseError
12
34
  def initialize(options)
13
35
  text = []
14
36
  text << "-- Client --"
data/lib/orcid/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Orcid
2
- VERSION = '0.8.0'
2
+ VERSION = '0.8.1'
3
3
  end
data/orcid.gemspec CHANGED
@@ -13,7 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.email = [
14
14
  'jeremy.n.friesen@gmail.com'
15
15
  ]
16
- s.homepage = 'https://github.com/jeremyf/orcid'
16
+ s.homepage = 'https://github.com/projecthydra-labs/orcid'
17
+ s.metadata = {
18
+ 'source' => 'https://github.com/projecthydra-labs/orcid',
19
+ 'issue_tracker' => 'https://github.com/projecthydra-labs/orcid/issues'
20
+ }
17
21
  s.summary = 'A Rails engine for orcid.org integration.'
18
22
  s.description = 'A Rails engine for orcid.org integration.'
19
23
 
@@ -96,7 +96,7 @@ module Orcid
96
96
 
97
97
  it 'should render a profile request form' do
98
98
  Orcid::ProfileRequest.should_receive(:find_by_user).with(user).and_return(nil)
99
- Orcid.should_receive(:enqueue).with(an_instance_of(Orcid::ProfileRequest))
99
+ Orcid::ProfileRequestCoordinator.should_receive(:call).with(an_instance_of(Orcid::ProfileRequest))
100
100
 
101
101
  expect do
102
102
  post :create, profile_request: profile_request_attributes, use_route: :orcid
@@ -106,7 +106,7 @@ module Orcid
106
106
 
107
107
  it 'should handle invalid data' do
108
108
  Orcid::ProfileRequest.should_receive(:find_by_user).with(user).and_return(nil)
109
- Orcid.should_not_receive(:enqueue)
109
+ Orcid::ProfileRequestCoordinator.should_not_receive(:call)
110
110
 
111
111
  expect do
112
112
  post :create, profile_request: {}, use_route: :orcid
@@ -21,6 +21,7 @@ describe 'non-UI based interactions' , requires_net_connect: true do
21
21
  let(:profile_request) {
22
22
  FactoryGirl.create(:orcid_profile_request, user: user, primary_email: email, primary_email_confirmation: email)
23
23
  }
24
+ let(:profile_request_coordinator) { Orcid::ProfileRequestCoordinator.new(profile_request)}
24
25
 
25
26
  before(:each) do
26
27
  # Making sure things are properly setup
@@ -28,7 +29,8 @@ describe 'non-UI based interactions' , requires_net_connect: true do
28
29
  end
29
30
 
30
31
  it 'creates a profile' do
31
- profile_request.run
32
+ profile_request_coordinator.call
33
+ profile_request.reload
32
34
 
33
35
  orcid_profile_id = profile_request.orcid_profile_id
34
36
 
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'orcid work query', requires_net_connect: true do
4
+ around(:each) do |example|
5
+ WebMock.allow_net_connect!
6
+ example.run
7
+ WebMock.disable_net_connect!
8
+ end
9
+ Given(:token) { Orcid.client_credentials_token('/read-public') }
10
+
11
+ # This profile exists on the Sandbox. But for how long? Who knows.
12
+ Given(:orcid_profile_id) { '0000-0002-1117-8571' }
13
+ Given(:remote_work_service) { Orcid::Remote::WorkService.new(orcid_profile_id, method: :get, token: token) }
14
+ Given(:remote_work_document) { remote_work_service.call }
15
+ When(:works) { Orcid::Work::XmlParser.call(remote_work_document) }
16
+ Then { expect(works.size).to_not be 0 }
17
+ end
@@ -0,0 +1,33 @@
1
+ require 'fast_helper'
2
+ require 'orcid/exceptions'
3
+
4
+ module Orcid
5
+ describe BaseError do
6
+ it { should be_a_kind_of RuntimeError }
7
+ end
8
+
9
+ describe ProfileRequestStateError do
10
+ subject { described_class }
11
+ its(:superclass) { should be BaseError }
12
+ end
13
+
14
+ describe MissingUserForProfileRequest do
15
+ subject { described_class }
16
+ its(:superclass) { should be BaseError }
17
+ end
18
+
19
+ describe ConfigurationError do
20
+ subject { described_class }
21
+ its(:superclass) { should be BaseError }
22
+ end
23
+
24
+ describe RemoteServiceError do
25
+ subject { described_class }
26
+ its(:superclass) { should be BaseError }
27
+ end
28
+
29
+ describe ProfileRequestMethodExpectedError do
30
+ subject { described_class }
31
+ its(:superclass) { should be BaseError }
32
+ end
33
+ end
@@ -8,6 +8,7 @@ describe Orcid do
8
8
  its(:provider) { should respond_to :secret }
9
9
  its(:mapper) { should respond_to :map }
10
10
  its(:use_relative_model_naming?) { should eq true }
11
+ its(:table_name_prefix) { should be_an_instance_of String }
11
12
 
12
13
  context '.authentication_model' do
13
14
  subject { Orcid.authentication_model }
@@ -1,19 +1,23 @@
1
- require 'spec_helper'
1
+ require 'fast_helper'
2
+ require 'orcid/profile_connection'
2
3
 
3
4
  # :nodoc:
4
5
  module Orcid
5
6
  describe ProfileConnection do
6
7
  let(:email) { 'test@hello.com' }
7
8
  let(:dois) { '123' }
8
- let(:user) { FactoryGirl.build_stubbed(:user) }
9
+ let(:user) { double('User') }
9
10
  let(:profile_query_service) { double('Profile Lookup Service') }
11
+ let(:persister) { double('Persister') }
10
12
 
11
13
  subject do
12
14
  Orcid::ProfileConnection.new(email: email, user: user).tap do |pc|
15
+ pc.persister = persister
13
16
  pc.profile_query_service = profile_query_service
14
17
  end
15
18
  end
16
19
 
20
+ its(:default_persister) { should respond_to(:call) }
17
21
  its(:email) { should eq email }
18
22
  its(:to_model) { should eq subject }
19
23
  its(:user) { should eq user }
@@ -53,7 +57,6 @@ module Orcid
53
57
 
54
58
  context '#save' do
55
59
  let(:orcid_profile_id) { '1234-5678' }
56
- let(:persister) { double('Persister') }
57
60
 
58
61
  it 'should call the persister when valid' do
59
62
  subject.orcid_profile_id = orcid_profile_id
@@ -61,15 +64,14 @@ module Orcid
61
64
  with(user, orcid_profile_id).
62
65
  and_return(:persisted)
63
66
 
64
- expect(subject.save(persister: persister)).to eq(:persisted)
67
+ expect(subject.save).to eq(:persisted)
65
68
  end
66
69
 
67
70
  it 'should NOT call the persister and add errors when not valid' do
68
71
  subject.user = nil
69
72
  subject.orcid_profile_id = nil
70
73
 
71
- expect { subject.save(persister: persister) }.
72
- to change { subject.errors.count }.by(2)
74
+ expect { subject.save }.to change { subject.errors.count }.by(2)
73
75
  end
74
76
  end
75
77
 
@@ -27,104 +27,22 @@ module Orcid
27
27
 
28
28
  end
29
29
 
30
- context '#handle_profile_creation_response' do
31
- it 'should update local' do
30
+ context '#successful_profile_creation' do
31
+ it 'should update profile request' do
32
32
  # Don't want to hit the database
33
33
  subject.should_receive(:update_column).with(:orcid_profile_id, orcid_profile_id)
34
34
  Orcid.should_receive(:connect_user_and_orcid_profile).with(user, orcid_profile_id)
35
35
 
36
- subject.handle_profile_creation_response(orcid_profile_id)
36
+ subject.successful_profile_creation(orcid_profile_id)
37
37
  end
38
38
  end
39
39
 
40
- context '#xml_payload' do
41
- it 'should be a parsable XML document' do
42
- expect {
43
- ActiveSupport::XmlMini.parse(subject.xml_payload)
44
- }.to_not raise_error
45
- end
46
- end
47
-
48
- context '#validate_before_run' do
49
- let(:orcid_profile) { double('Orcid Profile', to_param: orcid_profile_id) }
50
-
51
- context 'when no orcid profile has been assigned' do
52
- before { Orcid.should_receive(:profile_for).with(user).and_return(nil) }
53
- it 'should return true' do
54
- expect(subject.validate_before_run).to eq(true)
55
- end
56
- end
57
-
58
- context 'orcid_profile_id is set' do
59
- before { subject.orcid_profile_id = orcid_profile_id }
60
-
61
- it 'should return false' do
62
- expect(subject.validate_before_run).to eq(false)
63
- end
64
-
65
- it 'should set an error' do
66
- expect {
67
- subject.validate_before_run
68
- }.to change { subject.errors.full_messages.count }.by(1)
69
- end
70
-
71
- end
72
-
73
- context 'user has an orcid_profile' do
74
- before { Orcid.should_receive(:profile_for).with(user).and_return(orcid_profile) }
75
-
76
- it 'should return false' do
77
- expect(subject.validate_before_run).to eq(false)
78
- end
79
-
80
- it 'should set an error' do
81
- expect {
82
- subject.validate_before_run
83
- }.to change { subject.errors.full_messages.count }.by(1)
84
- end
85
-
86
- end
87
- end
88
-
89
- context '#run' do
90
- let(:profile_creation_service) { double('Profile Creation Service') }
91
- let(:payload_xml_builder) { double('Payload Xml Builder') }
92
- let(:validator) { double('Submission Guardian') }
93
- let(:xml_payload) { double('Xml Payload') }
94
-
95
- context 'with the submission guardian permitting the request' do
96
- before(:each) do
97
- validator.should_receive(:call).with(subject).
98
- and_return(true)
99
- payload_xml_builder.should_receive(:call).with(subject.attributes).
100
- and_return(xml_payload)
101
- profile_creation_service.should_receive(:call).with(xml_payload).
102
- and_return(orcid_profile_id)
103
- end
104
-
105
- it 'should run a request and handle the response' do
106
- subject.run(
107
- payload_xml_builder: payload_xml_builder,
108
- profile_creation_service: profile_creation_service,
109
- validator: validator
110
- )
111
- end
112
- end
113
-
114
- context 'with the submission guardian returning false' do
115
- before(:each) do
116
- validator.should_receive(:call).with(subject).
117
- and_return(false)
118
- payload_xml_builder.should_not_receive(:call)
119
- end
120
-
121
- it 'should raise an exception' do
122
- subject.run(
123
- payload_xml_builder: payload_xml_builder,
124
- profile_creation_service: profile_creation_service,
125
- validator: validator
126
- )
127
- end
40
+ context '#validation_error_on_profile_creation' do
41
+ it 'should update profile request' do
42
+ error_message = '123'
43
+ # Don't want to hit the database
44
+ subject.should_receive(:update_column).with(:response_text, error_message)
45
+ subject.validation_error_on_profile_creation(error_message)
128
46
  end
129
47
  end
130
48
  end