orcid 0.1.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +2 -1
  3. data/CONTRIBUTING.md +213 -0
  4. data/README.md +2 -5
  5. data/app/controllers/orcid/profile_requests_controller.rb +11 -1
  6. data/app/models/orcid/profile_connection.rb +12 -2
  7. data/app/models/orcid/profile_status.rb +67 -0
  8. data/app/services/orcid/remote/profile_creation_service.rb +15 -0
  9. data/app/services/orcid/remote/profile_query_service/response_parser.rb +53 -0
  10. data/app/services/orcid/remote/profile_query_service.rb +4 -23
  11. data/app/views/orcid/profile_connections/_authenticated_connection.html.erb +5 -0
  12. data/app/views/orcid/profile_connections/_options_to_connect_orcid_profile.html.erb +20 -0
  13. data/app/views/orcid/profile_connections/_orcid_connector.html.erb +15 -18
  14. data/app/views/orcid/profile_connections/_pending_connection.html.erb +11 -0
  15. data/app/views/orcid/profile_connections/_profile_request_pending.html.erb +5 -0
  16. data/config/locales/orcid.en.yml +1 -1
  17. data/lib/orcid/configuration/provider.rb +8 -0
  18. data/lib/orcid/version.rb +1 -1
  19. data/lib/orcid.rb +4 -0
  20. data/spec/controllers/orcid/profile_requests_controller_spec.rb +21 -9
  21. data/spec/features/public_api_query_spec.rb +6 -0
  22. data/spec/fixtures/orcid-remote-profile_query_service-response_parser/multiple-responses-without-valid-response.json +258 -0
  23. data/spec/fixtures/orcid-remote-profile_query_service-response_parser/single-response-with-orcid-valid-profile.json +71 -0
  24. data/spec/lib/orcid/configuration/provider_spec.rb +3 -0
  25. data/spec/lib/orcid_spec.rb +8 -0
  26. data/spec/models/orcid/profile_connection_spec.rb +39 -17
  27. data/spec/models/orcid/profile_status_spec.rb +73 -0
  28. data/spec/routing/orcid/profile_request_routing_spec.rb +15 -0
  29. data/spec/services/orcid/remote/profile_creation_service_spec.rb +23 -3
  30. data/spec/services/orcid/remote/profile_query_service/response_parser_spec.rb +43 -0
  31. data/spec/services/orcid/remote/profile_query_service_spec.rb +7 -89
  32. data/spec/views/orcid/profile_connections/_authenticated_connection.html.erb_spec.rb +20 -0
  33. data/spec/views/orcid/profile_connections/_options_to_connect_orcid_profile.html.erb_spec.rb +26 -0
  34. data/spec/views/orcid/profile_connections/_orcid_connector.html.erb_spec.rb +65 -0
  35. data/spec/views/orcid/profile_connections/_pending_connection.html.erb_spec.rb +22 -0
  36. data/spec/views/orcid/profile_connections/_profile_request_pending.html.erb_spec.rb +24 -0
  37. metadata +29 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 72fe44a31b834e45dc65efebc06f416ec6452908
4
- data.tar.gz: 93a589d4b5992b70e1ca685f1b50b37b9695efe6
3
+ metadata.gz: cdbf8eaf74801c8b3c9d2325d362d14e7f7e3c8b
4
+ data.tar.gz: dc2b890ba3958416489f364983885bf6a08a0f85
5
5
  SHA512:
6
- metadata.gz: c8ce12e869d4935a7e7c563a2b760630a42b8139d3f1fbe8c0d73a66b05d00b4b8be6a7ad1ee97b6baf8744be2606bd39cadf00b7d33c63155c0be9ef77935be
7
- data.tar.gz: 04a0d325084d3023aefc595abefe659ce126e57a81aae12d62949c308eec60a00c02bedbee72ccc9e7077795c1084f21ea9a0360adaf0767007ea5892efb6fdb
6
+ metadata.gz: 18825277ac23c713d06fad1ead3df6565bf1273fcb77cb53e01839cd7a5e443c7fad3f17cc4eefa1c70a73d4a69d7a03e5c1b5999d187a421a40c2ed0f8fd7ed
7
+ data.tar.gz: 3737282f7a406c4ca10cae3f2d51b315d512278c834680c20c57821f140864d2e0188a888a6a89eb0ff1a6f3f5df9ec0cf93cb9354d493121f19683062a6aa3e
data/.hound.yml CHANGED
@@ -187,6 +187,7 @@ Documentation:
187
187
 
188
188
  DotPosition:
189
189
  Description: 'Checks the position of the dot in multi-line method calls.'
190
+ EnforcedStyle: trailing
190
191
  Enabled: true
191
192
 
192
193
  DoubleNegation:
@@ -235,7 +236,7 @@ EvenOdd:
235
236
 
236
237
  FileName:
237
238
  Description: 'Use snake_case for source file names.'
238
- Enabled: true
239
+ Enabled: false
239
240
 
240
241
  FlipFlop:
241
242
  Description: 'Checks for flip flops'
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,213 @@
1
+ We want your help to make our project great.
2
+ There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
3
+
4
+ * [The Hydra Way](#the-hydra-way)
5
+ * [Reporting Issues](#reporting-issues)
6
+ * [What is a well written issue?](#what-is-a-well-written-issue)
7
+ * [Making Changes](#making-changes)
8
+ * [Where to Engage for Help](#where-to-engage-for-help)
9
+ * [Submitting Changes](#submitting-changes)
10
+ * [Contributor License Agreement](#contributor-license-agreement)
11
+ * [Coding Guidelines](#coding-guidelines)
12
+ * [Stating Your Intent](#stating-your-intent)
13
+ * [Writing Your Specs](#writing-your-specs)
14
+ * [Writing Your Code](#writing-your-code)
15
+ * [Ruby File Structure](#ruby-file-structure)
16
+ * [Well Written Commit Messages](#well-written-commit-messages)
17
+ * [Hooks into other Subsystems](#hooks-into-other-subsystems)
18
+ * [Reviewing Changes](#reviewing-changes)
19
+ * [Responsibilities of a Reviewer](#responsibilities-of-a-reviewer)
20
+ * [Responsibilities of the Submitter](#responsibilities-of-the-submitter)
21
+ * [Merging Changes](#merging-changes)
22
+
23
+ # The Hydra Way
24
+
25
+ We strive to…
26
+
27
+ * Provide a [harassment-free community experience](https://wiki.duraspace.org/display/hydra/Anti-Harassment+Policy)
28
+ * Adhere to our [Hierarchy of Promises](https://wiki.duraspace.org/display/hydra/Hydra+Stack+-+The+Hierarchy+of+Promises)
29
+ * Operate under [Lazy Consensus](http://rave.apache.org/docs/governance/lazyConsensus.html)
30
+ * Encourage community participation as guided by [our community principles](https://wiki.duraspace.org/display/hydra/Hydra+Community+Principles)
31
+
32
+ # Reporting Issues
33
+
34
+ Submit a [well written issue](#what-is-a-well-written-issue) to [Github's issue tracker](./issues).
35
+ This will require a [GitHub account](https://github.com/signup/free) *(its free)*.
36
+
37
+ ## What is a well written issue?
38
+
39
+ * Provide a descriptive summary
40
+ * Reference the version in which you encountered the problem
41
+ * Explain the expected behavior
42
+ * Explain the actual behavior
43
+ * Provide steps to reproduce the actual behavior
44
+
45
+ # Making Changes
46
+
47
+ Hydra is an open source project, released under the [APACHE 2 license](LICENSE).
48
+ You are free to clone or [fork the repository](https://help.github.com/articles/fork-a-repo) and modify the code as you see fit.
49
+
50
+ ## Where to Engage for Help
51
+
52
+ This gem is part of ProjectHydra, so you can [connect via the usual ProjectHydra channels](https://wiki.duraspace.org/pages/viewpage.action?pageId=43910187).
53
+
54
+ # Submitting Changes
55
+
56
+ ## Contributor License Agreement
57
+
58
+ **Note: You can submit a pull request before you've signed the Contributor License Agreement, but we won't merge your changes until we have your CLA on file.**
59
+
60
+ Before any [ProjectHydra project](https://github.com/projecthydra) can accept your contributions we must have a [Contributor License Agreement on file](https://wiki.duraspace.org/display/hydra/Hydra+Project+Intellectual+Property+Licensing+and+Ownership).
61
+
62
+ All code contributors must have an Individual Contributor License Agreement (iCLA) on file with the Hydra Project Steering Group.
63
+ If the contributor works for an institution, the institution must have a Corporate Contributor License Agreement (cCLA) on file.
64
+
65
+ [More on the Contributor License Agreements](https://wiki.duraspace.org/display/hydra/Hydra+Project+Intellectual+Property+Licensing+and+Ownership)
66
+
67
+ ## Coding Guidelines
68
+
69
+ This project is using [HoundCI](https://houndci.com) to help support our agreed upon style guide.
70
+ The style guide is a work in progress, and is declared in the project's `./hound.yml` file.
71
+
72
+ Hound is a Github integration tool that essentially runs [rubocop](http://rubygems.org/gems/rubocop).
73
+
74
+ > Automatic Ruby code style checking tool. Aims to enforce the community-driven Ruby Style Guide.
75
+
76
+ If you want to run `rubocop` with our style guide, first `gem install rubocop` then inside the project:
77
+
78
+ ```bash
79
+ $ rubocop ./path/to/file ./or/path/to/directory -c ./.hound.yml
80
+ ```
81
+ **Can I break these guidelines?** Yes.
82
+ But you may need to convince the person merging your changes.
83
+
84
+ ### Stating Your Intent
85
+
86
+ Think of your written test as a statement of intent.
87
+ The statement of intent can then be used when asking for help or clarity;
88
+ Either from another developer or a stakeholder.
89
+ Someone helping you can then see both what you are trying to do and how you are doing it;
90
+ And that helper may know of a "better" way to do it.
91
+
92
+ ### Writing Your Specs
93
+
94
+ Your code changes should include supporting tests.
95
+
96
+ Before you begin writing code, think about the test that will verify the code you plan to write.
97
+ A [well written story with Gherkin syntax](http://pivotallabs.com/well-formed-stories/) can help formulate the pre-conditions (Given), invocation (When), and post-conditions (Then).
98
+
99
+ *This is the first step of Test Driven Development, and something that we encourage.*
100
+
101
+ Now write that test; It should be your guidepost for any changes you plan on making.
102
+ The test you just wrote should be executable code;
103
+ If you are uncomfortable with where to put the executable code, a well formed Gherkin-syntax story is a suitable proxy.
104
+
105
+ ### Writing Your Code
106
+
107
+ We are going to do our best to follow [Sandi Metz' Rules for Developers](http://robots.thoughtbot.com/post/50655960596/sandi-metz-rules-for-developers)
108
+
109
+ > Here are the rules:
110
+ >
111
+ > * Classes can be no longer than one hundred lines of code.
112
+ > * Methods can be no longer than five lines of code.
113
+ > * Pass no more than four parameters into a method. Hash options are parameters.
114
+ > * Controllers can instantiate only one object. Therefore, views can only know about one instance variable and views should only send messages to that object (`@object.collaborator.value` is not allowed).
115
+
116
+ ## Well Written Commit Messages
117
+
118
+ **TL;DR**
119
+
120
+ * First line is 50 characters or less
121
+ * The message body explains what the code changes are about
122
+ * [Reference any Github issues](https://help.github.com/articles/writing-on-github#references) on new lines.
123
+ * It is helpful if you [close a related issue via the commit message](https://help.github.com/articles/closing-issues-via-commit-messages)
124
+
125
+ ### Terse Example
126
+
127
+ ```
128
+ Removing Document title validation
129
+
130
+ We thought we wanted title validation but that was too complicated.
131
+
132
+ Closes #12
133
+ ```
134
+
135
+ ### Verbose Example
136
+
137
+ ```
138
+ Present tense short summary (50 characters or less)
139
+
140
+ More detailed description, if necessary. It should be wrapped to 72
141
+ characters. Try to be as descriptive as you can, even if you think that
142
+ the commit content is obvious, it may not be obvious to others. You
143
+ should add such description also if it's already present in bug tracker,
144
+ it should not be necessary to visit a webpage to check the history.
145
+
146
+ Description can have multiple paragraphs and you can use code examples
147
+ inside, just indent it with 4 spaces:
148
+
149
+ class PostsController
150
+ def index
151
+ respond_with Post.limit(10)
152
+ end
153
+ end
154
+
155
+ You can also add bullet points:
156
+
157
+ - you can use dashes or asterisks
158
+
159
+ - also, try to indent next line of a point for readability, if it's too
160
+ long to fit in 72 characters
161
+ ```
162
+
163
+ > When appropriate, please squash your commits into logical units of work.
164
+ > This simplifies future cherry picks, and also keeps the git log clean.
165
+
166
+ ### Hooks into other Subsystems
167
+
168
+ **[ci skip]**: If your commit does not need to go through the Continuous Integration server, add `[ci skip]` to your commit message.
169
+ This is used for updates to the documentation and stylesheet changes.
170
+
171
+ # Reviewing Changes
172
+
173
+ The review process is a conversation between the submitter and the team as a whole.
174
+ Please feel free to bring other people into the conversation as necessary.
175
+
176
+ As either the submitter or reviewer, feel free to assign the Pull Request to a repository contributor.
177
+ This is a way of indicating that you want that repository contributor to review the change.
178
+
179
+ When you do assign someone to the Pull Request, please make sure to add a comment stating why you assigned it to them.
180
+
181
+ ## Responsibilities of a Reviewer
182
+
183
+ As a reviewer, it is important that the pull request:
184
+
185
+ * Has a [well written commit message](#well-written-commit-messages)
186
+ * Has [well written code](#coding-guidelines)
187
+ * All tests pass in the test suite
188
+ * Any questions regarding the pull request are answered
189
+ * Adjudicate if the Pull Request should be squashed into a smaller number of commits
190
+
191
+ ## Responsibilities of the Submitter
192
+
193
+ **As the submitter**, you should be responsive to the review process:
194
+
195
+ * answering questions
196
+ * making refinements
197
+ * providing clarification
198
+ * rebasing your commits.
199
+
200
+ *If your changes are gridlocked please notify [@jeremyf](https://github.com/jeremyf) via a comment on the pull request.*
201
+
202
+ # Merging Changes
203
+
204
+ *If a pull request has received at least one Thumbs Up, but has still not been merged, please notify [@jeremyf](https://github.com/jeremyf) via a comment on the pull request.*
205
+
206
+ **As the submitter,** you should not merge your own pull request.
207
+ That is bad form.
208
+
209
+ **As the reviewer,** if you are comfortable merge the pull request.
210
+ Otherwise feel free to assign the pull request to another contributor for final merging.
211
+
212
+ **As the merger,** once you have merged the pull request, go ahead and delete the pull request's topic branch.
213
+ You are now on the hook for any breaking of the build.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Orcid [![Version](https://badge.fury.io/rb/orcid.png)](http://badge.fury.io/rb/orcid) [![Build Status](https://travis-ci.org/jeremyf/orcid.png?branch=master)](https://travis-ci.org/jeremyf/orcid)
1
+ # Orcid [![Version](https://badge.fury.io/rb/orcid.png)](http://badge.fury.io/rb/orcid) [![Build Status](https://travis-ci.org/projecthydra-labs/orcid.png?branch=master)](https://travis-ci.org/projecthydra-labs/orcid)
2
2
 
3
3
  A [Rails Engine](https://guides.rubyonrails.org/engines.html) for integrating with [Orcid](https://orcid.org).
4
4
 
@@ -9,6 +9,7 @@ To fully interact with the Orcid remote services, you will need to [register you
9
9
  * [Registering for an ORCID application profile](#registering-for-an-orcid-application-profile)
10
10
  * [Setting up your own ORCIDs in the ORCID Development Sandbox](#setting-up-your-own-orcids-in-the-orcid-development-sandbox)
11
11
  * [Running the tests](#running-the-tests)
12
+ * [Contributing to this gem](./CONTRIBUTING.md)
12
13
 
13
14
  ## Installation
14
15
 
@@ -120,7 +121,3 @@ Run the online tests with
120
121
  ```console
121
122
  $ rake spec:online
122
123
  ```
123
-
124
- ## TODO Items
125
-
126
- * When searching for your profile, expose Name and associated DOI as query parameters.
@@ -25,7 +25,17 @@ module Orcid
25
25
  return false if redirecting_because_user_has_existing_profile_request
26
26
  assign_attributes(new_profile_request)
27
27
  create_profile_request(new_profile_request)
28
- respond_with(orcid, new_profile_request)
28
+ # As a named singular resource, url_for(profile_request) treates the
29
+ # input profile_request as the :format paramter. When you run
30
+ # `$ rake app:routes` in this gem, there is not a named route for:
31
+ # GET /profile_request(.:format) orcid/profile_requests#show
32
+ #
33
+ # Thus we need to pass the location.
34
+ if new_profile_request.valid?
35
+ respond_with(orcid, location: orcid.profile_request_path)
36
+ else
37
+ respond_with(orcid, new_profile_request)
38
+ end
29
39
  end
30
40
 
31
41
  protected
@@ -7,8 +7,9 @@ module Orcid
7
7
  include ActiveModel::Conversion
8
8
  extend ActiveModel::Naming
9
9
 
10
+ # See: http://support.orcid.org/knowledgebase/articles/132354-tutorial-searching-with-the-api
10
11
  class_attribute :available_query_attribute_names
11
- self.available_query_attribute_names = [:email, :text]
12
+ self.available_query_attribute_names = [:email, :text, :digital_object_ids]
12
13
 
13
14
  available_query_attribute_names.each do |attribute_name|
14
15
  attribute attribute_name
@@ -68,7 +69,16 @@ module Orcid
68
69
  private :query_requested?
69
70
 
70
71
  def query_attributes
71
- attributes.slice(*available_query_attribute_names)
72
+ available_query_attribute_names.each_with_object({}) do |name, mem|
73
+ orcid_formatted_name = convert_attribute_name_to_orcid_format(name)
74
+ mem[orcid_formatted_name] = attributes.fetch(name)
75
+ mem
76
+ end
77
+ end
78
+
79
+ def convert_attribute_name_to_orcid_format(name)
80
+ name.to_s.gsub(/_+/, '-')
72
81
  end
82
+ private :convert_attribute_name_to_orcid_format
73
83
  end
74
84
  end
@@ -0,0 +1,67 @@
1
+ module Orcid
2
+ # ProfileStatus.status
3
+ # **:authenticated_connection** - User has authenticated against the Orcid
4
+ # remote system
5
+ # **:pending_connection** - User has indicated there is a connection, but has
6
+ # not authenticated against the Orcid remote system
7
+ # **:profile_request_pending** - User has requested a profile be created on
8
+ # their behalf
9
+ # **:unknown** - None of the above
10
+ class ProfileStatus
11
+ def self.for(user, collaborators = {}, &block)
12
+ new(user, collaborators, &block).status
13
+ end
14
+
15
+ attr_reader :user, :profile_finder, :request_finder, :callback_handler
16
+
17
+ def initialize(user, collaborators = {})
18
+ @user = user
19
+ @profile_finder = collaborators.fetch(:profile_finder) { default_profile_finder }
20
+ @request_finder = collaborators.fetch(:request_finder) { default_request_finder }
21
+ @callback_handler = collaborators.fetch(:callback_handler) { default_callback_handler }
22
+ yield(callback_handler) if block_given?
23
+ end
24
+
25
+ def status
26
+ return callback(:unknown) if user.nil?
27
+ profile = profile_finder.call(user)
28
+ if profile
29
+ if profile.verified_authentication?
30
+ return callback(:authenticated_connection, profile)
31
+ else
32
+ return callback(:pending_connection, profile)
33
+ end
34
+ else
35
+ request = request_finder.call(user)
36
+ if request
37
+ return callback(:profile_request_pending, request)
38
+ else
39
+ return callback(:unknown)
40
+ end
41
+ end
42
+ return callback(:unknown)
43
+ end
44
+
45
+ private
46
+
47
+ def callback(name, *args)
48
+ callback_handler.call(name, *args)
49
+ name
50
+ end
51
+
52
+ def default_callback_handler
53
+ require 'orcid/named_callbacks'
54
+ NamedCallbacks.new
55
+ end
56
+
57
+ def default_profile_finder
58
+ require 'orcid'
59
+ Orcid.method(:profile_for)
60
+ end
61
+
62
+ def default_request_finder
63
+ require 'orcid/profile_request'
64
+ ProfileRequest.method(:find_by_user)
65
+ end
66
+ end
67
+ end
@@ -1,4 +1,6 @@
1
1
  require 'orcid/remote/service'
2
+ require 'oauth2/error'
3
+ require 'nokogiri'
2
4
  module Orcid
3
5
  module Remote
4
6
  # Responsible for minting a new ORCID for the given payload.
@@ -20,6 +22,8 @@ module Orcid
20
22
  def call(payload)
21
23
  response = deliver(payload)
22
24
  parse(response)
25
+ rescue ::OAuth2::Error => e
26
+ parse_exception(e)
23
27
  end
24
28
 
25
29
  protected
@@ -40,6 +44,17 @@ module Orcid
40
44
  end
41
45
  end
42
46
 
47
+ def parse_exception(exception)
48
+ doc = Nokogiri::XML.parse(exception.response.body)
49
+ error_text = doc.css('error-desc').text
50
+ if error_text.to_s.size > 0
51
+ callback(:orcid_validation_error, error_text)
52
+ false
53
+ else
54
+ fail exception
55
+ end
56
+ end
57
+
43
58
  def default_headers
44
59
  {
45
60
  'Accept' => 'application/xml',
@@ -0,0 +1,53 @@
1
+ require_dependency 'orcid/remote/profile_query_service'
2
+ module Orcid
3
+ module Remote
4
+ class ProfileQueryService
5
+ class ResponseParser
6
+
7
+ # A convenience method to expose entry into the ResponseParser function
8
+ def self.call(document, collaborators = {})
9
+ new(collaborators).call(document)
10
+ end
11
+
12
+ attr_reader :response_builder, :logger
13
+
14
+ 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
21
+ end
22
+
23
+ def call(document)
24
+ json = JSON.parse(document)
25
+ json.fetch('orcid-search-results').fetch('orcid-search-result')
26
+ .each_with_object([]) do |result, returning_value|
27
+ profile = result.fetch('orcid-profile')
28
+ begin
29
+ identifier = profile.fetch('orcid-identifier').fetch('path')
30
+ orcid_bio = profile.fetch('orcid-bio')
31
+ given_names = orcid_bio.fetch('personal-details').fetch('given-names').fetch('value')
32
+ family_name = orcid_bio.fetch('personal-details').fetch('family-name').fetch('value')
33
+ emails = []
34
+ contact_details = orcid_bio['contact-details']
35
+ if contact_details
36
+ emails = (contact_details['email'] || []).map {|email| email.fetch('value') }
37
+ end
38
+ label = "#{given_names} #{family_name}"
39
+ label << ' (' << emails.join(', ') << ')' if emails.any?
40
+ label << " [ORCID: #{identifier}]"
41
+ biography = ''
42
+ biography = orcid_bio['biography']['value'] if orcid_bio['biography']
43
+ returning_value << response_builder.new('id' => identifier, 'label' => label, 'biography' => biography)
44
+ rescue KeyError => e
45
+ logger.warn("Unexpected ORCID JSON Response, part of the response has been ignored.\tException Encountered:#{e.class}\t#{e}")
46
+ end
47
+ returning_value
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -9,11 +9,12 @@ module Orcid
9
9
  end
10
10
 
11
11
  attr_reader :token, :path, :headers, :response_builder, :query_builder
12
+ attr_reader :parser
12
13
  def initialize(config = {}, &callbacks)
13
14
  super(&callbacks)
14
15
  @query_builder = config.fetch(:query_parameter_builder) { QueryParameterBuilder }
15
16
  @token = config.fetch(:token) { default_token }
16
- @response_builder = config.fetch(:response_builder) { SearchResponse }
17
+ @parser = config.fetch(:parser) { ResponseParser }
17
18
  @path = config.fetch(:path) { 'v1.1/search/orcid-bio/' }
18
19
  @headers = config.fetch(:headers) { default_headers }
19
20
  end
@@ -41,7 +42,7 @@ module Orcid
41
42
  end
42
43
 
43
44
  def issue_callbacks(search_results)
44
- if search_results.any?
45
+ if Array(search_results).flatten.compact.any?
45
46
  callback(:found, search_results)
46
47
  else
47
48
  callback(:not_found)
@@ -54,27 +55,7 @@ module Orcid
54
55
  end
55
56
 
56
57
  def parse(document)
57
- json = JSON.parse(document)
58
-
59
- json.fetch('orcid-search-results').fetch('orcid-search-result')
60
- .each_with_object([]) do |result, returning_value|
61
- profile = result.fetch('orcid-profile')
62
- identifier = profile.fetch('orcid-identifier').fetch('path')
63
- orcid_bio = profile.fetch('orcid-bio')
64
- given_names = orcid_bio.fetch('personal-details').fetch('given-names').fetch('value')
65
- family_name = orcid_bio.fetch('personal-details').fetch('family-name').fetch('value')
66
- emails = []
67
- contact_details = orcid_bio['contact-details']
68
- if contact_details
69
- emails = (contact_details['email'] || []).map {|email| email.fetch('value') }
70
- end
71
- label = "#{given_names} #{family_name}"
72
- label << ' (' << emails.join(', ') << ')' if emails.any?
73
- label << " [ORCID: #{identifier}]"
74
- biography = ''
75
- biography = orcid_bio['biography']['value'] if orcid_bio['biography']
76
- returning_value << response_builder.new('id' => identifier, 'label' => label, 'biography' => biography)
77
- end
58
+ parser.call(document)
78
59
  end
79
60
 
80
61
  end
@@ -0,0 +1,5 @@
1
+ <div class="authenticated-connection">
2
+ <p>
3
+ Your ORCID (<a class="orcid-profile-id" href="<%= Orcid.url_for_orcid_id(authenticated_connection.orcid_profile_id)%>" ><%= authenticated_connection.orcid_profile_id %></a>) has been authenticated for this application.
4
+ </p>
5
+ </div>
@@ -0,0 +1,20 @@
1
+ <% profile_connection = Orcid::ProfileConnection.new %>
2
+ <% default_search_text = '' unless defined?(default_search_text) %>
3
+ <div class="options-to-connect-orcid-profile">
4
+ <p>
5
+ <%= link_to t('orcid/profile_connection.look_up_your_existing_orcid', scope: 'helpers.label'), orcid.new_profile_connection_path(profile_connection:{text: default_search_text}) %>
6
+ </p>
7
+ <p>
8
+ <%= link_to t('orcid/profile_connection.create_an_orcid', scope: 'helpers.label'), orcid.new_profile_request_path %>
9
+ </p>
10
+ <p>
11
+ <%= form_for(profile_connection, as: :profile_connection, url: orcid.profile_connections_path, method: :post) do |f| %>
12
+ <%# Note the `scope: 'helpers.label'` option is the default for the label, but I want to call those specifically out %>
13
+ <%= f.label :orcid_profile_id, t('orcid/profile_connection.orcid_profile_id', scope: 'helpers.label') %>
14
+ <%= f.text_field :orcid_profile_id, class:"orcid-input" %>
15
+ <button type="submit" class="search-submit btn btn-primary" id="keyword-search-submit" tabindex="2">
16
+ <span class="orcid-connect"><%= t('orcid/profile_connection.connect_button_text', scope: 'helpers.label') %></span>
17
+ </button>
18
+ <% end %>
19
+ </p>
20
+ </div>
@@ -1,22 +1,19 @@
1
- <% profile_connection = Orcid::ProfileConnection.new %>
2
- <% default_search_text = '' unless defined?(default_search_text) %>
1
+ <% defined?(status_processor) || status_processor = Orcid::ProfileStatus.method(:for) %>
3
2
  <div class='orcid-connector'>
4
3
  <h3><i class="icon-user"></i> <%= link_to t('orcid.verbose_name'), 'http://orcid.org/' %></h3>
5
- <p>
6
- <%= link_to t('orcid/profile_connection.look_up_your_existing_orcid', scope: 'helpers.label'), orcid.new_profile_connection_path(profile_connection:{text: default_search_text}) %>
7
- </p>
8
- <p>
9
- <%= link_to t('orcid/profile_connection.create_an_orcid', scope: 'helpers.label'), orcid.new_profile_request_path %>
10
- </p>
11
- <p>
12
- <%= form_for(profile_connection, as: :profile_connection, url: orcid.profile_connections_path, method: :post) do |f| %>
13
- <%# Note the `scope: 'helpers.label'` option is the default for the label, but I want to call those specifically out %>
14
- <%= f.label :orcid_profile_id, value: t('orcid/profile_connection.connect_button_text', scope: 'helpers.label') %>
15
- <%= f.text_field :orcid_profile_id, class:"orcid-input" %>
16
- <button type="submit" class="search-submit btn btn-primary" id="keyword-search-submit" tabindex="2">
17
- <span class="orcid-connect"><%= t('orcid/profile_connection.connect_button_text', scope: 'helpers.label') %></span>
18
- </button>
4
+ <% status_processor.call(current_user) do |on|%>
5
+ <% on.profile_request_pending do |pending_request| %>
6
+ <%= render partial: 'orcid/profile_connections/profile_request_pending', object: pending_request %>
7
+ <% end %>
8
+ <% on.authenticated_connection do |profile| %>
9
+ <%= render partial: 'orcid/profile_connections/authenticated_connection', object: profile %>
10
+ <% end %>
11
+ <% on.pending_connection do |profile| %>
12
+ <%= render partial: 'orcid/profile_connections/pending_connection', object: profile %>
13
+ <% end %>
14
+ <% on.unknown do %>
15
+ <% defined?(default_search_text) || default_search_text = '' %>
16
+ <%= render template: 'orcid/profile_connections/_options_to_connect_orcid_profile', locals: { default_search_text: default_search_text } %>
17
+ <% end %>
19
18
  <% end %>
20
- </p>
21
19
  </div>
22
-
@@ -0,0 +1,11 @@
1
+ <div class="pending-connection">
2
+ <p>
3
+ You have an ORCID (<a class="orcid-profile-id" href="<%= Orcid.url_for_orcid_id(pending_connection.orcid_profile_id)%>" ><%= pending_connection.orcid_profile_id %></a>).
4
+ </p>
5
+ <p>However, your ORCID has not been verified by this system. There are a few possibilities:
6
+ <ul>
7
+ <li>You may not have claimed your ORCID. <a class="find-out-more" href="http://support.orcid.org/knowledgebase/articles/164480-creating-claiming-new-records">Find out more about claiming your ORCID.</a></li>
8
+ <li>You have claimed your ORCID, but have not used it to <%= link_to('sign into this application', user_omniauth_authorize_path(provider: 'orcid'), class: 'signin-via-orcid') %>.</li>
9
+ </ul>
10
+ </p>
11
+ </div>
@@ -0,0 +1,5 @@
1
+ <div class="profile-request-pending">
2
+ <p>We are processing your ORCID Profile Request. It was submitted
3
+ <time datetime="<%= profile_request_pending.created_at.in_time_zone %>"><%= time_ago_in_words(profile_request_pending.created_at) %></time> ago.
4
+ </p>
5
+ </div>
@@ -30,7 +30,7 @@ en:
30
30
  messages:
31
31
  profile_connection_not_found: "Unable to find an existing Orcid Profile connection."
32
32
  verified_profile_connection_exists: "You have already connected and verified your Orcid Profile (%{orcid_profile_id})."
33
- verbose_name: Open Researcher and Contributor ID (ORCID)'
33
+ verbose_name: Open Researcher and Contributor ID (ORCID)
34
34
  helpers:
35
35
  label:
36
36
  orcid/profile_connection:
@@ -40,6 +40,14 @@ module Orcid
40
40
  end
41
41
  end
42
42
 
43
+ attr_writer :host_url
44
+ def host_url
45
+ @host_url ||= store.fetch('ORCID_HOST_URL') do
46
+ uri = URI.parse(signin_via_json_url)
47
+ "#{uri.scheme}://#{uri.host}"
48
+ end
49
+ end
50
+
43
51
  attr_writer :authorize_url
44
52
  def authorize_url
45
53
  @authorize_url ||= store.fetch('ORCID_AUTHORIZE_URL') do
data/lib/orcid/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Orcid
2
- VERSION = '0.1.1'
2
+ VERSION = '0.8.0'
3
3
  end
data/lib/orcid.rb CHANGED
@@ -71,6 +71,10 @@ module Orcid
71
71
  object.run
72
72
  end
73
73
 
74
+ def url_for_orcid_id(orcid_profile_id)
75
+ File.join(provider.host_url, orcid_profile_id)
76
+ end
77
+
74
78
  def oauth_client
75
79
  # passing the site: option as Orcid's Sandbox has an invalid certificate
76
80
  # for the api.sandbox.orcid.org