orcid 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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