Class: SulOrcidClient

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/sul_orcid_client.rb,
lib/sul_orcid_client/version.rb,
lib/sul_orcid_client/work_mapper.rb,
lib/sul_orcid_client/cocina_support.rb,
lib/sul_orcid_client/contributor_mapper.rb

Overview

Client for interacting with ORCID API rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: CocinaSupport, ContributorMapper, InvalidTokenError, WorkMapper

Constant Summary collapse

VERSION =
'0.9.0'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#base_auth_urlObject

Returns the value of attribute base_auth_url.



40
41
42
# File 'lib/sul_orcid_client.rb', line 40

def base_auth_url
  @base_auth_url
end

#base_public_urlObject

Returns the value of attribute base_public_url.



40
41
42
# File 'lib/sul_orcid_client.rb', line 40

def base_public_url
  @base_public_url
end

#base_urlObject

Returns the value of attribute base_url.



40
41
42
# File 'lib/sul_orcid_client.rb', line 40

def base_url
  @base_url
end

#client_idObject

Returns the value of attribute client_id.



40
41
42
# File 'lib/sul_orcid_client.rb', line 40

def client_id
  @client_id
end

#client_secretObject

Returns the value of attribute client_secret.



40
41
42
# File 'lib/sul_orcid_client.rb', line 40

def client_secret
  @client_secret
end

Class Method Details

.configure(client_id:, client_secret:, base_url:, base_public_url:, base_auth_url:) ⇒ Object

Parameters:

  • client_id (String)

    the client identifier registered with Orcid

  • client_secret (String)

    the client secret to authenticate with Orcid

  • base_url (String)

    the base URL for the API

  • base_public_url (String)

    the base public URL for the API

  • base_auth_url (String)

    the base authorization URL for the API



28
29
30
31
32
33
34
35
# File 'lib/sul_orcid_client.rb', line 28

def configure(client_id:, client_secret:, base_url:, base_public_url:, base_auth_url:)
  instance.base_url = base_url
  instance.base_public_url = base_public_url
  instance.client_id = client_id
  instance.client_secret = client_secret
  instance.base_auth_url = base_auth_url
  self
end

Instance Method Details

#add_work(orcidid:, work:, token:) ⇒ string

Add a new work for a researcher.

Parameters:

  • ORCID (string)

    ID for the researcher

  • work (Hash)

    in correct data structure for ORCID work

  • access (string)

    token

Returns:

  • (string)

    put-code



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/sul_orcid_client.rb', line 109

def add_work(orcidid:, work:, token:)
  response = conn_with_token(token).post("/v3.0/#{base_orcidid(orcidid)}/work",
                                         work.to_json,
                                         'Content-Type' => 'application/json')

  case response.status
  when 201
    response['Location'].match(%r{work/(\d+)})[1]
  when 401
    raise InvalidTokenError,
          "Invalid token for #{orcidid} - ORCID.org API returned #{response.status} (#{response.body})"
  when 409
    match = response.body.match(/put-code (\d+)\./)
    raise 'ORCID.org API returned a 409, but could not find put-code' unless match

    match[1]
  else
    raise "ORCID.org API returned #{response.status} (#{response.body}) for: #{work.to_json}"
  end
end

#delete_work(orcidid:, put_code:, token:) ⇒ boolean

Delete a work

Parameters:

  • ORCID (string)

    ID for the researcher

  • put-code (string)
  • access (string)

    token

Returns:

  • (boolean)

    true if delete succeeded



159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/sul_orcid_client.rb', line 159

def delete_work(orcidid:, put_code:, token:)
  response = conn_with_token(token).delete("/v3.0/#{base_orcidid(orcidid)}/work/#{put_code}")

  case response.status
  when 204
    true
  when 404
    false
  else
    raise "ORCID.org API returned #{response.status} when deleting #{put_code} for #{orcidid}"
  end
end

#fetch_name(orcidid:) ⇒ Object

Fetches the name for a user given an orcidid rubocop:disable Metrics/MethodLength



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/sul_orcid_client.rb', line 57

def fetch_name(orcidid:)
  match = /[0-9xX]{4}-[0-9xX]{4}-[0-9xX]{4}-[0-9xX]{4}/.match(orcidid)
  raise 'invalid orcidid provided' unless match

  response = public_conn.get("/v3.0/#{match[0]&.upcase}/personal-details")
  case response.status
  when 200
    resp_json = JSON.parse(response.body)
    [resp_json.dig('name', 'given-names', 'value'),
     resp_json.dig('name', 'family-name', 'value')]
  else
    raise "ORCID.org API returned #{response.status} (#{response.body}) for: #{orcidid}"
  end
end

#fetch_work(orcidid:, put_code:) ⇒ Object

Fetch the details for a work



51
52
53
# File 'lib/sul_orcid_client.rb', line 51

def fetch_work(orcidid:, put_code:)
  get("/v3.0/#{base_orcidid(orcidid)}/work/#{put_code}")
end

#fetch_works(orcidid:) ⇒ Hash

Fetch the works for a researcher. Model for the response: https://pub.orcid.org/v3.0/#!/Development_Public_API_v3.0/viewWorksv3

Parameters:

  • ORCID (string)

    ID for the researcher

Returns:

  • (Hash)


46
47
48
# File 'lib/sul_orcid_client.rb', line 46

def fetch_works(orcidid:)
  get("/v3.0/#{base_orcidid(orcidid)}/works")
end

#search(query:, expanded: false) ⇒ Object

Run a generalized search query against ORCID see https://info.orcid.org/documentation/api-tutorials/api-tutorial-searching-the-orcid-registry rubocop:disable Metrics/AbcSize

Parameters:

  • query (query)

    to pass to ORCID

  • set (expanded)

    to true or false (defaults to false) to indicate an expanded query results (see ORCID docs)



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/sul_orcid_client.rb', line 77

def search(query:, expanded: false)
  if expanded
    search_method = 'expanded-search'
    response_name = 'expanded-result'
  else
    search_method = 'search'
    response_name = 'result'
  end

  # this is the maximum number of rows ORCID allows in their response currently
  max_num_returned = 1000
  total_response = get("/v3.0/#{search_method}/?q=#{query}&rows=#{max_num_returned}")
  num_results = total_response['num-found']

  return total_response if num_results <= max_num_returned

  num_pages = (num_results / max_num_returned.to_f).ceil

  # we already have page 1 of the results
  (1..num_pages - 1).each do |page_num| # rubocop:disable Lint/AmbiguousRange
    response = get("/v3.0/#{search_method}/?q=#{query}&start=#{(page_num * max_num_returned) + 1}&rows=#{max_num_returned}")
    total_response[response_name] += response[response_name]
  end

  total_response
end

#update_work(orcidid:, work:, token:, put_code:) ⇒ Boolean

Update an existing work for a researcher.

Parameters:

  • orcidid (String)

    an ORCiD ID for the researcher

  • work (Hash)

    a work in correct data structure for ORCID work

  • token (String)

    an ORCiD API access token

  • put_code (String)

    the PUT code

Returns:

  • (Boolean)

    true if update succeeded

Raises:

  • (RuntimeError)

    if the API response status is not successful



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/sul_orcid_client.rb', line 139

def update_work(orcidid:, work:, token:, put_code:)
  response = conn_with_token(token).put("/v3.0/#{base_orcidid(orcidid)}/work/#{put_code}",
                                        work.merge({ 'put-code' => put_code }).to_json,
                                        'Content-Type' => 'application/vnd.orcid+json')

  if response.status == 404
    raise "ORCID.org API returned #{response.status} when updating #{put_code} for #{orcidid}. The author may have previously deleted " \
          'this work from their ORCID profile.'
  end

  raise "ORCID.org API returned #{response.status} when updating #{put_code} for #{orcidid}" unless response.status == 200

  true
end