orcid 0.1.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hound.yml +2 -1
- data/CONTRIBUTING.md +213 -0
- data/README.md +2 -5
- data/app/controllers/orcid/profile_requests_controller.rb +11 -1
- data/app/models/orcid/profile_connection.rb +12 -2
- data/app/models/orcid/profile_status.rb +67 -0
- data/app/services/orcid/remote/profile_creation_service.rb +15 -0
- data/app/services/orcid/remote/profile_query_service/response_parser.rb +53 -0
- data/app/services/orcid/remote/profile_query_service.rb +4 -23
- data/app/views/orcid/profile_connections/_authenticated_connection.html.erb +5 -0
- data/app/views/orcid/profile_connections/_options_to_connect_orcid_profile.html.erb +20 -0
- data/app/views/orcid/profile_connections/_orcid_connector.html.erb +15 -18
- data/app/views/orcid/profile_connections/_pending_connection.html.erb +11 -0
- data/app/views/orcid/profile_connections/_profile_request_pending.html.erb +5 -0
- data/config/locales/orcid.en.yml +1 -1
- data/lib/orcid/configuration/provider.rb +8 -0
- data/lib/orcid/version.rb +1 -1
- data/lib/orcid.rb +4 -0
- data/spec/controllers/orcid/profile_requests_controller_spec.rb +21 -9
- data/spec/features/public_api_query_spec.rb +6 -0
- data/spec/fixtures/orcid-remote-profile_query_service-response_parser/multiple-responses-without-valid-response.json +258 -0
- data/spec/fixtures/orcid-remote-profile_query_service-response_parser/single-response-with-orcid-valid-profile.json +71 -0
- data/spec/lib/orcid/configuration/provider_spec.rb +3 -0
- data/spec/lib/orcid_spec.rb +8 -0
- data/spec/models/orcid/profile_connection_spec.rb +39 -17
- data/spec/models/orcid/profile_status_spec.rb +73 -0
- data/spec/routing/orcid/profile_request_routing_spec.rb +15 -0
- data/spec/services/orcid/remote/profile_creation_service_spec.rb +23 -3
- data/spec/services/orcid/remote/profile_query_service/response_parser_spec.rb +43 -0
- data/spec/services/orcid/remote/profile_query_service_spec.rb +7 -89
- data/spec/views/orcid/profile_connections/_authenticated_connection.html.erb_spec.rb +20 -0
- data/spec/views/orcid/profile_connections/_options_to_connect_orcid_profile.html.erb_spec.rb +26 -0
- data/spec/views/orcid/profile_connections/_orcid_connector.html.erb_spec.rb +65 -0
- data/spec/views/orcid/profile_connections/_pending_connection.html.erb_spec.rb +22 -0
- data/spec/views/orcid/profile_connections/_profile_request_pending.html.erb_spec.rb +24 -0
- metadata +29 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdbf8eaf74801c8b3c9d2325d362d14e7f7e3c8b
|
4
|
+
data.tar.gz: dc2b890ba3958416489f364983885bf6a08a0f85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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:
|
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/
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
<%
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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>
|
data/config/locales/orcid.en.yml
CHANGED
@@ -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
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
|