qa 4.2.4 → 4.3.0
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.
- checksums.yaml +5 -5
- data/app/controllers/qa/linked_data_terms_controller.rb +16 -51
- data/app/services/qa/linked_data/authority_url_service.rb +35 -21
- data/app/services/qa/linked_data/request_header_service.rb +97 -0
- data/lib/qa/authorities/discogs/generic_authority.rb +26 -29
- data/lib/qa/authorities/linked_data/find_term.rb +47 -25
- data/lib/qa/authorities/linked_data/search_query.rb +43 -15
- data/lib/qa/authorities/loc/generic_authority.rb +2 -2
- data/lib/qa/version.rb +1 -1
- data/spec/controllers/terms_controller_spec.rb +2 -2
- data/spec/lib/authorities/discogs/generic_authority_spec.rb +7 -7
- data/spec/lib/authorities/linked_data/find_term_spec.rb +11 -11
- data/spec/lib/authorities/linked_data/search_query_spec.rb +9 -9
- data/spec/lib/authorities/loc_spec.rb +9 -9
- data/spec/services/linked_data/authority_url_service_spec.rb +14 -8
- data/spec/services/linked_data/request_header_service_spec.rb +124 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7e4ee1da3b72cee5194380a24b44e96793395d110cbe2234da55541da3f962c9
|
4
|
+
data.tar.gz: 27dffc56d77c9e583000c99823a31fe8c90f3591ea3de04935c4e476bda9d289
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad1a1bc75bcde5877679a355e7afec3f992e869686f3c3c706d5e1ffee6ecdcc66c4be4a8572c9ca1c27b6b177b12b211debc8a579268037aff006872d3e9b5a
|
7
|
+
data.tar.gz: 789919e7a524d155d69ae2ca0203900cc0509f613d94d3b2b14ed697e2c80134b9d13dd56fb013c9db052069296955f4b948b43ff95ae10f93e4dd2ccbd643d6
|
@@ -7,9 +7,15 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
7
7
|
before_action :check_show_subauthority, :check_id_param, only: :show
|
8
8
|
before_action :check_uri_param, only: :fetch
|
9
9
|
before_action :validate_auth_reload_token, only: :reload
|
10
|
+
before_action :create_request_header_service, only: [:search, :show, :fetch]
|
10
11
|
|
11
12
|
delegate :cors_allow_origin_header, to: Qa::ApplicationController
|
12
13
|
|
14
|
+
class_attribute :request_header_service_class
|
15
|
+
self.request_header_service_class = Qa::LinkedData::RequestHeaderService
|
16
|
+
|
17
|
+
attr_reader :request_header_service
|
18
|
+
|
13
19
|
# Provide a warning if there is a request for all terms.
|
14
20
|
def index
|
15
21
|
logger.warn 'Linked data authorities do not support retrieving all terms.'
|
@@ -35,8 +41,8 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
35
41
|
# Return a list of terms based on a query
|
36
42
|
# get "/search/linked_data/:vocab(/:subauthority)"
|
37
43
|
# @see Qa::Authorities::LinkedData::SearchQuery#search
|
38
|
-
def search # rubocop:disable Metrics/MethodLength
|
39
|
-
terms = @authority.search(query,
|
44
|
+
def search # rubocop:disable Metrics/MethodLength
|
45
|
+
terms = @authority.search(query, request_header: request_header_service.search_header)
|
40
46
|
cors_allow_origin_header(response)
|
41
47
|
render json: terms
|
42
48
|
rescue Qa::ServiceUnavailable
|
@@ -59,9 +65,9 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
59
65
|
# get "/show/linked_data/:vocab/:subauthority/:id
|
60
66
|
# @see Qa::Authorities::LinkedData::FindTerm#find
|
61
67
|
def show # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
62
|
-
term = @authority.find(id,
|
68
|
+
term = @authority.find(id, request_header: request_header_service.fetch_header)
|
63
69
|
cors_allow_origin_header(response)
|
64
|
-
render json: term, content_type: content_type_for_format
|
70
|
+
render json: term, content_type: request_header_service.content_type_for_format
|
65
71
|
rescue Qa::TermNotFound
|
66
72
|
msg = "Term Not Found - Fetch term #{id} unsuccessful for#{subauth_warn_msg} authority #{vocab_param}"
|
67
73
|
logger.warn msg
|
@@ -89,9 +95,9 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
89
95
|
# get "/fetch/linked_data/:vocab"
|
90
96
|
# @see Qa::Authorities::LinkedData::FindTerm#find
|
91
97
|
def fetch # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
92
|
-
term = @authority.find(uri,
|
98
|
+
term = @authority.find(uri, request_header: request_header_service.fetch_header)
|
93
99
|
cors_allow_origin_header(response)
|
94
|
-
render json: term, content_type: content_type_for_format
|
100
|
+
render json: term, content_type: request_header_service.content_type_for_format
|
95
101
|
rescue Qa::TermNotFound
|
96
102
|
msg = "Term Not Found - Fetch term #{uri} unsuccessful for#{subauth_warn_msg} authority #{vocab_param}"
|
97
103
|
logger.warn msg
|
@@ -147,6 +153,10 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
156
|
+
def create_request_header_service
|
157
|
+
@request_header_service = request_header_service_class.new(request, params)
|
158
|
+
end
|
159
|
+
|
150
160
|
def init_authority
|
151
161
|
@authority = Qa::Authorities::LinkedData::GenericAuthority.new(vocab_param)
|
152
162
|
rescue Qa::InvalidLinkedDataAuthority => e
|
@@ -190,64 +200,19 @@ class Qa::LinkedDataTermsController < ::ApplicationController
|
|
190
200
|
params[:id]
|
191
201
|
end
|
192
202
|
|
193
|
-
def language
|
194
|
-
request_language = request.env['HTTP_ACCEPT_LANGUAGE']
|
195
|
-
request_language = request_language.scan(/^[a-z]{2}/).first if request_language.present?
|
196
|
-
params[:lang] || request_language
|
197
|
-
end
|
198
|
-
|
199
203
|
def subauthority
|
200
204
|
params[:subauthority]
|
201
205
|
end
|
202
206
|
|
203
|
-
def replacement_params
|
204
|
-
params.reject { |k, _v| ['q', 'vocab', 'controller', 'action', 'subauthority', 'lang', 'id'].include?(k) }
|
205
|
-
end
|
206
|
-
|
207
207
|
def subauth_warn_msg
|
208
208
|
subauthority.blank? ? "" : " sub-authority #{subauthority} in"
|
209
209
|
end
|
210
210
|
|
211
|
-
def format
|
212
|
-
return 'json' unless params.key?(:format)
|
213
|
-
return 'json' if params[:format].blank?
|
214
|
-
params[:format]
|
215
|
-
end
|
216
|
-
|
217
|
-
def jsonld?
|
218
|
-
format.casecmp?('jsonld')
|
219
|
-
end
|
220
|
-
|
221
|
-
def n3?
|
222
|
-
format.casecmp?('n3')
|
223
|
-
end
|
224
|
-
|
225
|
-
def ntriples?
|
226
|
-
format.casecmp?('ntriples')
|
227
|
-
end
|
228
|
-
|
229
|
-
def content_type_for_format
|
230
|
-
return 'application/ld+json' if jsonld?
|
231
|
-
return 'text/n3' if n3?
|
232
|
-
return 'application/n-triples' if ntriples?
|
233
|
-
'application/json'
|
234
|
-
end
|
235
|
-
|
236
|
-
def context?
|
237
|
-
context = params.fetch(:context, 'false')
|
238
|
-
context.casecmp?('true')
|
239
|
-
end
|
240
|
-
|
241
211
|
def details?
|
242
212
|
details = params.fetch(:details, 'false')
|
243
213
|
details.casecmp?('true')
|
244
214
|
end
|
245
215
|
|
246
|
-
def performance_data?
|
247
|
-
performance_data = params.fetch(:performance_data, 'false')
|
248
|
-
performance_data.casecmp?('true')
|
249
|
-
end
|
250
|
-
|
251
216
|
def validate_auth_reload_token
|
252
217
|
token = params.key?(:auth_token) ? params[:auth_token] : nil
|
253
218
|
valid = Qa.config.valid_authority_reload_token?(token)
|
@@ -7,14 +7,17 @@ module Qa
|
|
7
7
|
# @param action_config [Qa::Authorities::LinkedData::SearchConfig | Qa::Authorities::LinkedData::TermConfig] action configuration for the authority
|
8
8
|
# @param action [Symbol] action with valid values :search or :term
|
9
9
|
# @param action_request [String] the request the user is making of the authority (e.g. query text or term id/uri)
|
10
|
-
# @param
|
11
|
-
# @
|
12
|
-
# @
|
10
|
+
# @param request_header [Hash] optional attributes that can be appended to the generated URL
|
11
|
+
# @option replacements [Hash] variable-value pairs to substitute into the URL template
|
12
|
+
# @option subauthority [String] name of a subauthority
|
13
|
+
# @option language [Array<Symbol>] languages for filtering returned literals
|
13
14
|
# @return a valid URL that submits the action request to the external authority
|
14
|
-
|
15
|
+
# @note All parameters after request_header are deprecated and will be removed in the next major release.
|
16
|
+
def build_url(action_config:, action:, action_request:, request_header: {}, substitutions: {}, subauthority: nil, language: nil) # rubocop:disable Metrics/ParameterLists
|
17
|
+
request_header = build_request_header(substitutions, subauthority, language) if request_header.empty?
|
15
18
|
action_validation(action)
|
16
19
|
url_config = action_config.url_config
|
17
|
-
selected_substitutions = url_config.extract_substitutions(combined_substitutions(action_config, action, action_request,
|
20
|
+
selected_substitutions = url_config.extract_substitutions(combined_substitutions(action_config, action, action_request, request_header))
|
18
21
|
Qa::IriTemplateService.build_url(url_config: url_config, substitutions: selected_substitutions)
|
19
22
|
end
|
20
23
|
|
@@ -25,10 +28,12 @@ module Qa
|
|
25
28
|
raise Qa::UnsupportedAction, "#{action} Not Supported - Action must be one of the supported actions (e.g. :term, :search)"
|
26
29
|
end
|
27
30
|
|
28
|
-
def combined_substitutions(action_config, action, action_request,
|
31
|
+
def combined_substitutions(action_config, action, action_request, request_header)
|
32
|
+
substitutions = request_header.fetch(:replacements, {})
|
29
33
|
substitutions[action_request_variable(action_config, action)] = action_request
|
30
|
-
substitutions[action_subauth_variable(action_config)] = action_subauth_variable_value(action_config,
|
31
|
-
substitutions[action_language_variable(action_config)] = language_value(
|
34
|
+
substitutions[action_subauth_variable(action_config)] = action_subauth_variable_value(action_config, request_header)
|
35
|
+
substitutions[action_language_variable(action_config)] = language_value(action_config, request_header)
|
36
|
+
substitutions.reject { |_k, v| v.nil? }
|
32
37
|
substitutions
|
33
38
|
end
|
34
39
|
|
@@ -37,29 +42,38 @@ module Qa
|
|
37
42
|
action_config.qa_replacement_patterns[key]
|
38
43
|
end
|
39
44
|
|
40
|
-
def supports_subauthorities?(action_config)
|
41
|
-
action_config.supports_subauthorities?
|
42
|
-
end
|
43
|
-
|
44
45
|
def action_subauth_variable(action_config)
|
45
46
|
action_config.qa_replacement_patterns[:subauth]
|
46
47
|
end
|
47
48
|
|
48
|
-
def action_subauth_variable_value(action_config,
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def supports_language_parameter?(action_config)
|
53
|
-
action_config.supports_language_parameter?
|
49
|
+
def action_subauth_variable_value(action_config, request_header)
|
50
|
+
subauth = request_header.fetch(:subauthority, nil)
|
51
|
+
return nil unless subauth && action_config.supports_subauthorities?
|
52
|
+
action_config.subauthorities[subauth.to_sym]
|
54
53
|
end
|
55
54
|
|
56
55
|
def action_language_variable(action_config)
|
57
56
|
action_config.qa_replacement_patterns[:lang]
|
58
57
|
end
|
59
58
|
|
60
|
-
def language_value(
|
61
|
-
return nil
|
62
|
-
language.first
|
59
|
+
def language_value(action_config, request_header)
|
60
|
+
return nil unless action_config.supports_language_parameter?
|
61
|
+
request_header.fetch(:language, []).first
|
62
|
+
end
|
63
|
+
|
64
|
+
# This is providing support for calling build_url with individual parameters instead of the request_header.
|
65
|
+
# This is deprecated and will be removed in the next major release.
|
66
|
+
def build_request_header(substitutions, subauthority, language) # rubocop:disable Metrics/CyclomaticComplexity
|
67
|
+
return {} if substitutions.blank? && subauthority.blank? && language.blank?
|
68
|
+
Qa.deprecation_warning(
|
69
|
+
in_msg: 'Qa::LinkedData::AuthorityUrlService',
|
70
|
+
msg: "individual attributes for options (e.g. substitutions, subauthority, language) are deprecated; use request_header instead"
|
71
|
+
)
|
72
|
+
request_header = {}
|
73
|
+
request_header[:replacements] = substitutions unless substititions.blank?
|
74
|
+
request_header[:subauthority] = subauthority unless subauthority.blank?
|
75
|
+
request_header[:language] = language unless language.blank?
|
76
|
+
request_header
|
63
77
|
end
|
64
78
|
end
|
65
79
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Service to construct a request header that includes optional attributes for search and fetch requests.
|
2
|
+
module Qa
|
3
|
+
module LinkedData
|
4
|
+
class RequestHeaderService
|
5
|
+
attr_reader :request, :params
|
6
|
+
|
7
|
+
# @param request [HttpRequest] request from controller
|
8
|
+
# @param params [Hash] attribute-value pairs holding the request parameters
|
9
|
+
# @option subauthority [String] the subauthority to query
|
10
|
+
# @option lang [Symbol] language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
|
11
|
+
# @option performance_data [Boolean] true if include_performance_data should be returned with the results; otherwise, false (default: false)
|
12
|
+
# @option context [Boolean] true if context should be returned with the results; otherwise, false (default: false) (search only)
|
13
|
+
# @option format [String] return data in this format (fetch only)
|
14
|
+
# @note params may have additional attribute-value pairs that are passed through via replacements (only configured replacements are used)
|
15
|
+
def initialize(request, params)
|
16
|
+
@request = request
|
17
|
+
@params = params
|
18
|
+
end
|
19
|
+
|
20
|
+
# Construct request parameters to pass to search_query (linked data module).
|
21
|
+
# @returns [Hash] parsed out attribute-value pairs that are required for the search query
|
22
|
+
# @see Qa::Authorities::LinkedData::SearchQuery
|
23
|
+
def search_header
|
24
|
+
header = {}
|
25
|
+
header[:subauthority] = params.fetch(:subauthority, nil)
|
26
|
+
header[:user_language] = user_language
|
27
|
+
header[:performance_data] = performance_data?
|
28
|
+
header[:context] = context?
|
29
|
+
header[:replacements] = replacements
|
30
|
+
header
|
31
|
+
end
|
32
|
+
|
33
|
+
# Construct request parameters to pass to fetching a term (linked data module).
|
34
|
+
# @returns [Hash] parsed out attribute-value pairs that are required for the term fetch.
|
35
|
+
# @see Qa::Authorities::LinkedData::FindTerm
|
36
|
+
def fetch_header
|
37
|
+
header = {}
|
38
|
+
header[:subauthority] = params.fetch(:subauthority, nil)
|
39
|
+
header[:user_language] = user_language
|
40
|
+
header[:performance_data] = performance_data?
|
41
|
+
header[:format] = format
|
42
|
+
header[:replacements] = replacements
|
43
|
+
header
|
44
|
+
end
|
45
|
+
|
46
|
+
# @returns [String] the response header content type based on requested format
|
47
|
+
def content_type_for_format
|
48
|
+
case format
|
49
|
+
when 'jsonld'
|
50
|
+
'application/ld+json'
|
51
|
+
when 'n3'
|
52
|
+
'text/n3'
|
53
|
+
when 'ntriples'
|
54
|
+
'application/n-triples'
|
55
|
+
else
|
56
|
+
'application/json'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# filter literals in results to this language
|
63
|
+
def user_language
|
64
|
+
request_language = request.env['HTTP_ACCEPT_LANGUAGE']
|
65
|
+
request_language = request_language.scan(/^[a-z]{2}/).first if request_language.present?
|
66
|
+
lang = params[:lang] || request_language
|
67
|
+
lang.present? ? Array(lang) : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# include extended context in the results if true (applies to search only)
|
71
|
+
def context?
|
72
|
+
context = params.fetch(:context, 'false')
|
73
|
+
context.casecmp?('true')
|
74
|
+
end
|
75
|
+
|
76
|
+
# include performance data in the results if true
|
77
|
+
def performance_data?
|
78
|
+
performance_data = params.fetch(:performance_data, 'false')
|
79
|
+
performance_data.casecmp?('true')
|
80
|
+
end
|
81
|
+
|
82
|
+
# any params not specifically handled are passed through via replacements
|
83
|
+
def replacements
|
84
|
+
params.reject do |k, _v|
|
85
|
+
['q', 'vocab', 'controller', 'action', 'subauthority', 'lang', 'id',
|
86
|
+
'context', 'performance_data', 'response_header', 'format'].include?(k)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# results are returned in the format (applies to fetch only)
|
91
|
+
def format
|
92
|
+
f = params.fetch(:format, 'json').downcase
|
93
|
+
['jsonld', 'n3', 'ntriples'].include?(f) ? f : 'json'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -101,30 +101,27 @@ module Qa::Authorities
|
|
101
101
|
|
102
102
|
# @param [Hash] the http response from discogs
|
103
103
|
# @example returns parsed discogs data with context
|
104
|
-
# {
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
# "release"
|
126
|
-
# ]
|
127
|
-
# }
|
104
|
+
# [{
|
105
|
+
# "uri": "https://www.discogs.com/Frank-Sinatra-And-The-Modernaires-Sorry-Why-Remind-Me/release/4212473",
|
106
|
+
# "id": "4212473",
|
107
|
+
# "label": "Frank Sinatra And The Modernaires - Sorry / Why Remind Me",
|
108
|
+
# "context": [{
|
109
|
+
# "property": "Image URL",
|
110
|
+
# "values": ["https://img.discogs.com/1358693671-5430.jpeg.jpg"]
|
111
|
+
# }, {
|
112
|
+
# "property": "Year",
|
113
|
+
# "values": ["1950"]
|
114
|
+
# }, {
|
115
|
+
# "property": "Record Labels",
|
116
|
+
# "values": ["Columbia"]
|
117
|
+
# }, {
|
118
|
+
# "property": "Formats",
|
119
|
+
# "values": ["Shellac", "10\"", "78 RPM"]
|
120
|
+
# }, {
|
121
|
+
# "property": "Type",
|
122
|
+
# "values": ["release"]
|
123
|
+
# }]
|
124
|
+
# }]
|
128
125
|
def parse_authority_response(response)
|
129
126
|
response['results'].map do |result|
|
130
127
|
{ 'uri' => build_uri(result),
|
@@ -141,11 +138,11 @@ module Qa::Authorities
|
|
141
138
|
|
142
139
|
# @param [Hash] the results hash from the JSON returned by Discogs
|
143
140
|
def assemble_search_context(result)
|
144
|
-
{ "Image URL" => get_context_for_string(result['cover_image']),
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
141
|
+
[{ "property" => "Image URL", "values" => get_context_for_string(result['cover_image']) },
|
142
|
+
{ "property" => "Year", "values" => get_context_for_string(result['year']) },
|
143
|
+
{ "property" => "Record Labels", "values" => get_context_for_array(result['label']) },
|
144
|
+
{ "property" => "Formats", "values" => get_context_for_array(result['format']) },
|
145
|
+
{ "property" => "Type", "values" => get_context_for_string(result['type']) }]
|
149
146
|
end
|
150
147
|
|
151
148
|
# checks if the param is null, returns appropriate value
|
@@ -15,17 +15,21 @@ module Qa::Authorities
|
|
15
15
|
@term_config = term_config
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :term_config, :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
19
|
-
private :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
18
|
+
attr_reader :term_config, :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size, :subauthority
|
19
|
+
private :full_graph, :filtered_graph, :language, :id, :uri, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size, :subauthority
|
20
20
|
|
21
21
|
delegate :term_subauthority?, :prefixes, :authority_name, to: :term_config
|
22
22
|
|
23
23
|
# Find a single term in a linked data authority
|
24
24
|
# @param [String] the id of the term to fetch
|
25
|
-
# @param [
|
26
|
-
# @
|
27
|
-
# @
|
28
|
-
# @
|
25
|
+
# @param request_header [Hash] optional attributes that can be appended to the generated URL
|
26
|
+
# @option language [Symbol] language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
|
27
|
+
# @option replacements [Hash] replacement values with { pattern_name (defined in YAML config) => value }
|
28
|
+
# @option subauthority [String] the subauthority from which to fetch the term
|
29
|
+
# @option format [String] return data in this format
|
30
|
+
# @option performance_data [Boolean] true if include_performance_data should be returned with the results; otherwise, false (default: false)
|
31
|
+
# @note All parameters after request_header are deprecated and will be removed in the next major release.
|
32
|
+
# @return [Hash, String] normalized json results when format='json'; otherwise, serialized RDF in the requested format
|
29
33
|
# @example Json Results for Linked Data Term
|
30
34
|
# { "uri":"http://id.worldcat.org/fast/530369",
|
31
35
|
# "id":"530369","label":"Cornell University",
|
@@ -39,21 +43,12 @@ module Qa::Authorities
|
|
39
43
|
# "http://schema.org/name":["Cornell University","Ithaca (N.Y.). Cornell University"],
|
40
44
|
# "http://www.w3.org/2004/02/skos/core#altLabel":["Ithaca (N.Y.). Cornell University"],
|
41
45
|
# "http://schema.org/sameAs":["http://id.loc.gov/authorities/names/n79021621","https://viaf.org/viaf/126293486"] } }
|
42
|
-
def find(id, language: nil, replacements: {}, subauth: nil, format:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
def find(id, request_header: {}, language: nil, replacements: {}, subauth: nil, format: 'json', performance_data: false) # rubocop:disable Metrics/ParameterLists
|
47
|
+
request_header = build_request_header(language: language, replacements: replacements, subauth: subauth, format: format, performance_data: performance_data) if request_header.empty?
|
48
|
+
unpack_request_header(request_header)
|
49
|
+
raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data term sub-authority #{subauthority}" unless subauthority.nil? || term_subauthority?(subauthority)
|
46
50
|
@id = id
|
47
|
-
|
48
|
-
@format = format
|
49
|
-
@jsonld = jsonld if @format.blank?
|
50
|
-
if jsonld
|
51
|
-
Qa.deprecation_warning(
|
52
|
-
in_msg: 'Qa::Authorities::LinkedData::FindTerm',
|
53
|
-
msg: "jsonld parameter to find method is deprecated; use `format: 'jsonld'` instead"
|
54
|
-
)
|
55
|
-
end
|
56
|
-
url = authority_service.build_url(action_config: term_config, action: :term, action_request: normalize_id, substitutions: replacements, subauthority: subauth, language: @language)
|
51
|
+
url = authority_service.build_url(action_config: term_config, action: :term, action_request: normalize_id, request_header: request_header)
|
57
52
|
Rails.logger.info "QA Linked Data term url: #{url}"
|
58
53
|
load_graph(url: url)
|
59
54
|
normalize_results
|
@@ -75,14 +70,14 @@ module Qa::Authorities
|
|
75
70
|
def normalize_results
|
76
71
|
normalize_start_dt = Time.now.utc
|
77
72
|
|
78
|
-
|
73
|
+
results = perform_normalization
|
79
74
|
|
80
75
|
normalize_end_dt = Time.now.utc
|
81
76
|
@normalize_time_s = normalize_end_dt - normalize_start_dt
|
82
|
-
@normalized_size =
|
83
|
-
Rails.logger.info("Time to
|
84
|
-
|
85
|
-
|
77
|
+
@normalized_size = results.to_s.size if performance_data?
|
78
|
+
Rails.logger.info("Time to normalize data: #{normalize_time_s}s")
|
79
|
+
results = append_performance_data(results) if performance_data?
|
80
|
+
results
|
86
81
|
end
|
87
82
|
|
88
83
|
def perform_normalization
|
@@ -97,6 +92,15 @@ module Qa::Authorities
|
|
97
92
|
convert_results_to_json(results)
|
98
93
|
end
|
99
94
|
|
95
|
+
def unpack_request_header(request_header)
|
96
|
+
@subauthority = request_header.fetch(:subauthority, nil)
|
97
|
+
@format = request_header.fetch(:format, 'json')
|
98
|
+
@performance_data = request_header.fetch(:performance_data, false)
|
99
|
+
@language = language_service.preferred_language(user_language: request_header.fetch(:user_language, nil),
|
100
|
+
authority_language: term_config.term_language)
|
101
|
+
request_header[:language] = Array(@language)
|
102
|
+
end
|
103
|
+
|
100
104
|
def filter_graph
|
101
105
|
@filtered_graph = graph_service.deep_copy(graph: @full_graph)
|
102
106
|
@filtered_graph = graph_service.filter(graph: @filtered_graph, language: language) unless language.blank?
|
@@ -290,6 +294,24 @@ module Qa::Authorities
|
|
290
294
|
total_time_s: (access_time_s + normalize_time_s) }
|
291
295
|
{ performance: performance, results: results }
|
292
296
|
end
|
297
|
+
|
298
|
+
# This is providing support for calling build_url with individual parameters instead of the request_header.
|
299
|
+
# This is deprecated and will be removed in the next major release.
|
300
|
+
def build_request_header(language:, replacements:, subauth:, format:, performance_data:) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
301
|
+
unless language.blank? && replacements.blank? && subauth.blank? && format == 'json' && !performance_data
|
302
|
+
Qa.deprecation_warning(
|
303
|
+
in_msg: 'Qa::Authorities::LinkedData::FindTerm',
|
304
|
+
msg: "individual attributes for options (e.g. replacements, subauth, language) are deprecated; use request_header instead"
|
305
|
+
)
|
306
|
+
end
|
307
|
+
request_header = {}
|
308
|
+
request_header[:replacements] = replacements || {}
|
309
|
+
request_header[:subauthority] = subauth || nil
|
310
|
+
request_header[:language] = language || nil
|
311
|
+
request_header[:format] = format || 'json'
|
312
|
+
request_header[:performance_data] = performance_data
|
313
|
+
request_header
|
314
|
+
end
|
293
315
|
end
|
294
316
|
end
|
295
317
|
end
|
@@ -15,29 +15,30 @@ module Qa::Authorities
|
|
15
15
|
@search_config = search_config
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :search_config, :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
19
|
-
private :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size
|
18
|
+
attr_reader :search_config, :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size, :subauthority
|
19
|
+
private :full_graph, :filtered_graph, :language, :access_time_s, :normalize_time_s, :fetched_size, :normalized_size, :subauthority
|
20
20
|
|
21
21
|
delegate :subauthority?, :supports_sort?, :prefixes, :authority_name, to: :search_config
|
22
22
|
|
23
23
|
# Search a linked data authority
|
24
24
|
# @praram [String] the query
|
25
|
-
# @param
|
26
|
-
# @
|
27
|
-
# @
|
28
|
-
# @
|
29
|
-
# @
|
25
|
+
# @param request_header [Hash] optional attributes that can be appended to the generated URL
|
26
|
+
# @option language [Symbol] language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
|
27
|
+
# @option replacements [Hash] replacement values with { pattern_name (defined in YAML config) => value }
|
28
|
+
# @option subauthority [String] the subauthority to query
|
29
|
+
# @option context [Boolean] true if context should be returned with the results; otherwise, false (default: false)
|
30
|
+
# @option performance_data [Boolean] true if include_performance_data should be returned with the results; otherwise, false (default: false)
|
30
31
|
# @return [String] json results
|
32
|
+
# @note All parameters after request_header are deprecated and will be removed in the next major release.
|
31
33
|
# @example Json Results for Linked Data Search
|
32
34
|
# [ {"uri":"http://id.worldcat.org/fast/5140","id":"5140","label":"Cornell, Joseph"},
|
33
35
|
# {"uri":"http://id.worldcat.org/fast/72456","id":"72456","label":"Cornell, Sarah Maria, 1802-1832"},
|
34
36
|
# {"uri":"http://id.worldcat.org/fast/409667","id":"409667","label":"Cornell, Ezra, 1807-1874"} ]
|
35
|
-
def search(query, language: nil, replacements: {}, subauth: nil, context: false, performance_data: false) # rubocop:disable Metrics/ParameterLists
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
url = authority_service.build_url(action_config: search_config, action: :search, action_request: query, substitutions: replacements, subauthority: subauth, language: @language)
|
37
|
+
def search(query, request_header: {}, language: nil, replacements: {}, subauth: nil, context: false, performance_data: false) # rubocop:disable Metrics/ParameterLists
|
38
|
+
request_header = build_request_header(language: language, replacements: replacements, subauth: subauth, context: context, performance_data: performance_data) if request_header.empty?
|
39
|
+
unpack_request_header(request_header)
|
40
|
+
raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data search sub-authority #{subauthority}" unless subauthority.nil? || subauthority?(subauthority)
|
41
|
+
url = authority_service.build_url(action_config: search_config, action: :search, action_request: query, request_header: request_header)
|
41
42
|
Rails.logger.info "QA Linked Data search url: #{url}"
|
42
43
|
load_graph(url: url)
|
43
44
|
normalize_results
|
@@ -66,7 +67,7 @@ module Qa::Authorities
|
|
66
67
|
normalize_end_dt = Time.now.utc
|
67
68
|
@normalize_time_s = normalize_end_dt - normalize_start_dt
|
68
69
|
@normalized_size = json.to_s.size if performance_data?
|
69
|
-
Rails.logger.info("Time to
|
70
|
+
Rails.logger.info("Time to normalize data: #{normalize_time_s}s")
|
70
71
|
json = append_performance_data(json) if performance_data?
|
71
72
|
json
|
72
73
|
end
|
@@ -87,7 +88,16 @@ module Qa::Authorities
|
|
87
88
|
|
88
89
|
results_mapper_service.map_values(graph: filtered_graph, prefixes: prefixes, ldpath_map: ldpath_map,
|
89
90
|
predicate_map: predicate_map, sort_key: :sort,
|
90
|
-
preferred_language:
|
91
|
+
preferred_language: language, context_map: context_map)
|
92
|
+
end
|
93
|
+
|
94
|
+
def unpack_request_header(request_header)
|
95
|
+
@subauthority = request_header.fetch(:subauthority, nil)
|
96
|
+
@context = request_header.fetch(:context, false)
|
97
|
+
@performance_data = request_header.fetch(:performance_data, false)
|
98
|
+
@language = language_service.preferred_language(user_language: request_header.fetch(:user_language, nil),
|
99
|
+
authority_language: search_config.language)
|
100
|
+
request_header[:language] = Array(@language)
|
91
101
|
end
|
92
102
|
|
93
103
|
def context_map
|
@@ -180,6 +190,24 @@ module Qa::Authorities
|
|
180
190
|
total_time_s: (access_time_s + normalize_time_s) }
|
181
191
|
{ performance: performance, results: results }
|
182
192
|
end
|
193
|
+
|
194
|
+
# This is providing support for calling build_url with individual parameters instead of the request_header.
|
195
|
+
# This is deprecated and will be removed in the next major release.
|
196
|
+
def build_request_header(language:, replacements:, subauth:, context:, performance_data:) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
197
|
+
unless language.blank? && replacements.blank? && subauth.blank? && !context && !performance_data
|
198
|
+
Qa.deprecation_warning(
|
199
|
+
in_msg: 'Qa::Authorities::LinkedData::SearchQuery',
|
200
|
+
msg: "individual attributes for options (e.g. replacements, subauth, language) are deprecated; use request_header instead"
|
201
|
+
)
|
202
|
+
end
|
203
|
+
request_header = {}
|
204
|
+
request_header[:replacements] = replacements || {}
|
205
|
+
request_header[:subauthority] = subauth || nil
|
206
|
+
request_header[:language] = language || nil
|
207
|
+
request_header[:context] = context
|
208
|
+
request_header[:performance_data] = performance_data
|
209
|
+
request_header
|
210
|
+
end
|
183
211
|
end
|
184
212
|
end
|
185
213
|
end
|
@@ -26,7 +26,7 @@ module Qa::Authorities
|
|
26
26
|
def build_query_url(q)
|
27
27
|
escaped_query = ERB::Util.url_encode(q)
|
28
28
|
authority_fragment = Loc.get_url_for_authority(subauthority) + ERB::Util.url_encode(subauthority)
|
29
|
-
"
|
29
|
+
"https://id.loc.gov/search/?q=#{escaped_query}&q=#{authority_fragment}&format=json"
|
30
30
|
end
|
31
31
|
|
32
32
|
def find(id)
|
@@ -34,7 +34,7 @@ module Qa::Authorities
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def find_url(id)
|
37
|
-
"
|
37
|
+
"https://id.loc.gov/authorities/#{@subauthority}/#{id}.json"
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
data/lib/qa/version.rb
CHANGED
@@ -82,7 +82,7 @@ describe Qa::TermsController, type: :controller do
|
|
82
82
|
|
83
83
|
context "loc" do
|
84
84
|
before do
|
85
|
-
stub_request(:get, "
|
85
|
+
stub_request(:get, "https://id.loc.gov/search/?format=json&q=Berry&q=cs:http://id.loc.gov/authorities/names")
|
86
86
|
.with(headers: { 'Accept' => 'application/json' })
|
87
87
|
.to_return(body: webmock_fixture("loc-names-response.txt"), status: 200)
|
88
88
|
end
|
@@ -188,7 +188,7 @@ describe Qa::TermsController, type: :controller do
|
|
188
188
|
describe "#show" do
|
189
189
|
context "with supported authorities" do
|
190
190
|
before do
|
191
|
-
stub_request(:get, "
|
191
|
+
stub_request(:get, "https://id.loc.gov/authorities/subjects/sh85077565.json")
|
192
192
|
.with(headers: { 'Accept' => 'application/json' })
|
193
193
|
.to_return(status: 200, body: webmock_fixture("loc-names-response.txt"), headers: {})
|
194
194
|
end
|
@@ -276,10 +276,10 @@ describe Qa::Authorities::Discogs::GenericAuthority do
|
|
276
276
|
expect(results.first["uri"]).to eq("https://www.discogs.com/Melody-Gardot-Who-Will-Comfort-Me-Over-The-Rainbow/release/1750352")
|
277
277
|
expect(results.first["id"]).to eq "1750352"
|
278
278
|
expect(results.first["label"]).to eq "Melody Gardot - Who Will Comfort Me / Over The Rainbow"
|
279
|
-
expect(results.first["context"]["
|
280
|
-
expect(results.first["context"]["
|
281
|
-
expect(results.first["context"]["
|
282
|
-
expect(results.first["context"]["
|
279
|
+
expect(results.first["context"][1]["values"]).to eq ["2009"]
|
280
|
+
expect(results.first["context"][3]["values"][0]).to eq "Vinyl"
|
281
|
+
expect(results.first["context"][2]["values"][1]).to eq "Universal Music Classics & Jazz"
|
282
|
+
expect(results.first["context"][4]["values"][0]).to eq "release"
|
283
283
|
end
|
284
284
|
end
|
285
285
|
|
@@ -299,9 +299,9 @@ describe Qa::Authorities::Discogs::GenericAuthority do
|
|
299
299
|
expect(results.first['uri']).to eq "https://www.discogs.com/Wes-Montgomery-Bumpin-On-Sunset-Tequila/master/606116"
|
300
300
|
expect(results.first['id']).to eq "606116"
|
301
301
|
expect(results.first['label']).to eq "Wes Montgomery - Bumpin' On Sunset / Tequila"
|
302
|
-
expect(results.first['context']["
|
303
|
-
expect(results.first['context']["
|
304
|
-
expect(results.first["context"]["
|
302
|
+
expect(results.first['context'][1]["values"]).to eq ['1966']
|
303
|
+
expect(results.first['context'][3]["values"][2]).to eq "45 RPM"
|
304
|
+
expect(results.first["context"][4]["values"][0]).to eq "master"
|
305
305
|
end
|
306
306
|
end
|
307
307
|
|
@@ -24,7 +24,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
24
24
|
end
|
25
25
|
context 'when set to true' do
|
26
26
|
let :results do
|
27
|
-
lod_oclc.find('530369', performance_data: true)
|
27
|
+
lod_oclc.find('530369', request_header: { performance_data: true })
|
28
28
|
end
|
29
29
|
it 'includes performance in return hash' do
|
30
30
|
expect(results.keys).to match_array [:performance, :results]
|
@@ -38,7 +38,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
38
38
|
|
39
39
|
context 'when set to false' do
|
40
40
|
let :results do
|
41
|
-
lod_oclc.find('530369', performance_data: false)
|
41
|
+
lod_oclc.find('530369', request_header: { performance_data: false })
|
42
42
|
end
|
43
43
|
it 'does NOT include performance in return hash' do
|
44
44
|
expect(results.keys).not_to include(:performance)
|
@@ -114,7 +114,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
114
114
|
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
115
115
|
end
|
116
116
|
|
117
|
-
let(:results) { lod_loc.find('sh 85118553',
|
117
|
+
let(:results) { lod_loc.find('sh 85118553', request_header: { subauthority: 'subjects' }) }
|
118
118
|
|
119
119
|
it 'has correct primary predicate values' do
|
120
120
|
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
@@ -182,8 +182,8 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
182
182
|
.to_return(status: 200, body: webmock_fixture('lod_loc_second_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
183
183
|
end
|
184
184
|
|
185
|
-
let(:results) { lod_loc.find('sh 85118553',
|
186
|
-
let(:second_results) { lod_loc.find('sh 1234',
|
185
|
+
let(:results) { lod_loc.find('sh 85118553', request_header: { subauthority: 'subjects' }) }
|
186
|
+
let(:second_results) { lod_loc.find('sh 1234', request_header: { subauthority: 'subjects' }) }
|
187
187
|
|
188
188
|
it 'has correct primary predicate values for second request' do
|
189
189
|
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
@@ -201,7 +201,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
201
201
|
.to_return(status: 200, body: webmock_fixture('lod_loc_term_found.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
202
202
|
end
|
203
203
|
|
204
|
-
let(:results_without_blank) { lod_loc.find('sh85118553',
|
204
|
+
let(:results_without_blank) { lod_loc.find('sh85118553', request_header: { subauthority: 'subjects' }) }
|
205
205
|
|
206
206
|
it 'extracts correct uri' do
|
207
207
|
expect(results_without_blank[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
@@ -215,7 +215,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
215
215
|
end
|
216
216
|
|
217
217
|
it 'raises DataNormalizationError' do
|
218
|
-
expect { lod_loc.find('sh85118553',
|
218
|
+
expect { lod_loc.find('sh85118553', request_header: { subauthority: 'subjects' }) }.to raise_error Qa::DataNormalizationError, "Unable to extract URI based on ID: sh85118553"
|
219
219
|
end
|
220
220
|
end
|
221
221
|
|
@@ -226,7 +226,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
226
226
|
allow(lod_loc.term_config).to receive(:authority_name).and_return('ALT_LOC_AUTHORITY')
|
227
227
|
end
|
228
228
|
|
229
|
-
let(:results) { lod_loc.find('sh 85118553',
|
229
|
+
let(:results) { lod_loc.find('sh 85118553', request_header: { subauthority: 'subjects' }) }
|
230
230
|
|
231
231
|
it 'does special processing to remove blank from id' do
|
232
232
|
expect(results[:uri]).to eq 'http://id.loc.gov/authorities/subjects/sh85118553'
|
@@ -313,7 +313,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
313
313
|
let :results do
|
314
314
|
stub_request(:get, "http://aims.fao.org/aos/agrovoc/c_9513")
|
315
315
|
.to_return(status: 200, body: webmock_fixture("lod_lang_term_enfr.rdf.xml"), headers: { 'Content-Type' => 'application/rdf+xml' })
|
316
|
-
lod_lang_defaults.find('http://aims.fao.org/aos/agrovoc/c_9513', language: 'fr')
|
316
|
+
lod_lang_defaults.find('http://aims.fao.org/aos/agrovoc/c_9513', request_header: { language: 'fr' })
|
317
317
|
end
|
318
318
|
it "is filtered to specified language" do
|
319
319
|
expect(results[:label]).to eq ['Babeurre']
|
@@ -328,7 +328,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
328
328
|
let :results do
|
329
329
|
stub_request(:get, "http://aims.fao.org/aos/agrovoc/c_9513")
|
330
330
|
.to_return(status: 200, body: webmock_fixture("lod_lang_term_enfr_noalt.rdf.xml"), headers: { 'Content-Type' => 'application/rdf+xml' })
|
331
|
-
lod_lang_defaults.find('http://aims.fao.org/aos/agrovoc/c_9513', language: 'fr')
|
331
|
+
lod_lang_defaults.find('http://aims.fao.org/aos/agrovoc/c_9513', request_header: { language: 'fr' })
|
332
332
|
end
|
333
333
|
it "is filtered to specified language" do
|
334
334
|
expect(results[:label]).to eq ['Babeurre']
|
@@ -357,7 +357,7 @@ RSpec.describe Qa::Authorities::LinkedData::FindTerm do
|
|
357
357
|
let :results do
|
358
358
|
stub_request(:get, "http://aims.fao.org/aos/agrovoc/c_9513?lang=fr")
|
359
359
|
.to_return(status: 200, body: webmock_fixture("lod_lang_term_fr.rdf.xml"), headers: { 'Content-Type' => 'application/rdf+xml' })
|
360
|
-
lod_lang_param.find('http://aims.fao.org/aos/agrovoc/c_9513', replacements: { 'lang' => 'fr' })
|
360
|
+
lod_lang_param.find('http://aims.fao.org/aos/agrovoc/c_9513', request_header: { replacements: { 'lang' => 'fr' } })
|
361
361
|
end
|
362
362
|
it "is correctly parsed" do
|
363
363
|
expect(results[:label]).to eq ['Babeurre']
|
@@ -11,7 +11,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
11
11
|
end
|
12
12
|
context 'when set to true' do
|
13
13
|
let :results do
|
14
|
-
lod_oclc.search('cornell',
|
14
|
+
lod_oclc.search('cornell', request_header: { subauthority: 'personal_name', replacements: { 'maximumRecords' => '3' }, performance_data: true })
|
15
15
|
end
|
16
16
|
it 'includes performance in return hash' do
|
17
17
|
expect(results).to be_kind_of Hash
|
@@ -27,7 +27,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
27
27
|
|
28
28
|
context 'when set to false' do
|
29
29
|
let :results do
|
30
|
-
lod_oclc.search('cornell',
|
30
|
+
lod_oclc.search('cornell', request_header: { subauthority: 'personal_name', replacements: { 'maximumRecords' => '3' }, performance_data: false })
|
31
31
|
end
|
32
32
|
it 'does NOT include performance in return hash' do
|
33
33
|
expect(results).to be_kind_of Array
|
@@ -36,7 +36,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
36
36
|
|
37
37
|
context 'when using default setting' do
|
38
38
|
let :results do
|
39
|
-
lod_oclc.search('cornell',
|
39
|
+
lod_oclc.search('cornell', request_header: { subauthority: 'personal_name', replacements: { 'maximumRecords' => '3' } })
|
40
40
|
end
|
41
41
|
it 'does NOT include performance in return hash' do
|
42
42
|
expect(results).to be_kind_of Array
|
@@ -49,7 +49,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
49
49
|
let :results do
|
50
50
|
stub_request(:get, 'http://experimental.worldcat.org/fast/search?maximumRecords=3&query=cql.any%20all%20%22supercalifragilisticexpialidocious%22&sortKeys=usage')
|
51
51
|
.to_return(status: 200, body: webmock_fixture('lod_oclc_query_no_results.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
52
|
-
lod_oclc.search('supercalifragilisticexpialidocious', replacements: { 'maximumRecords' => '3' })
|
52
|
+
lod_oclc.search('supercalifragilisticexpialidocious', request_header: { replacements: { 'maximumRecords' => '3' } })
|
53
53
|
end
|
54
54
|
it 'returns an empty array' do
|
55
55
|
expect(results).to eq([])
|
@@ -60,7 +60,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
60
60
|
let :results do
|
61
61
|
stub_request(:get, 'http://experimental.worldcat.org/fast/search?maximumRecords=3&query=cql.any%20all%20%22cornell%22&sortKeys=usage')
|
62
62
|
.to_return(status: 200, body: webmock_fixture('lod_oclc_all_query_3_results.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
63
|
-
lod_oclc.search('cornell', replacements: { 'maximumRecords' => '3' })
|
63
|
+
lod_oclc.search('cornell', request_header: { replacements: { 'maximumRecords' => '3' } })
|
64
64
|
end
|
65
65
|
it 'is correctly parsed' do
|
66
66
|
expect(results.count).to eq(3)
|
@@ -76,7 +76,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
76
76
|
let :results do
|
77
77
|
stub_request(:get, 'http://experimental.worldcat.org/fast/search?maximumRecords=3&query=oclc.personalName%20all%20%22supercalifragilisticexpialidocious%22&sortKeys=usage')
|
78
78
|
.to_return(status: 200, body: webmock_fixture('lod_oclc_query_no_results.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
79
|
-
lod_oclc.search('supercalifragilisticexpialidocious',
|
79
|
+
lod_oclc.search('supercalifragilisticexpialidocious', request_header: { subauthority: 'personal_name', replacements: { 'maximumRecords' => '3' } })
|
80
80
|
end
|
81
81
|
it 'returns an empty array' do
|
82
82
|
expect(results).to eq([])
|
@@ -87,7 +87,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
87
87
|
let :results do
|
88
88
|
stub_request(:get, 'http://experimental.worldcat.org/fast/search?maximumRecords=3&query=oclc.personalName%20all%20%22cornell%22&sortKeys=usage')
|
89
89
|
.to_return(status: 200, body: webmock_fixture('lod_oclc_personalName_query_3_results.rdf.xml'), headers: { 'Content-Type' => 'application/rdf+xml' })
|
90
|
-
lod_oclc.search('cornell',
|
90
|
+
lod_oclc.search('cornell', request_header: { subauthority: 'personal_name', replacements: { 'maximumRecords' => '3' } })
|
91
91
|
end
|
92
92
|
it 'is correctly parsed' do
|
93
93
|
expect(results.count).to eq(3)
|
@@ -197,7 +197,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
197
197
|
let :results do
|
198
198
|
stub_request(:get, "http://localhost/test_default/search?query=milk")
|
199
199
|
.to_return(status: 200, body: webmock_fixture("lod_lang_search_enfr.rdf.xml"), headers: { 'Content-Type' => 'application/rdf+xml' })
|
200
|
-
lod_lang_defaults.search('milk', language: :fr)
|
200
|
+
lod_lang_defaults.search('milk', request_header: { language: :fr })
|
201
201
|
end
|
202
202
|
it "is filtered to specified language" do
|
203
203
|
expect(results.first[:label]).to eq('Babeurre (délicieux)')
|
@@ -226,7 +226,7 @@ RSpec.describe Qa::Authorities::LinkedData::SearchQuery do
|
|
226
226
|
let :results do
|
227
227
|
stub_request(:get, "http://localhost/test_replacement/search?query=milk&lang=fr")
|
228
228
|
.to_return(status: 200, body: webmock_fixture("lod_lang_search_fr.rdf.xml"), headers: { 'Content-Type' => 'application/rdf+xml' })
|
229
|
-
lod_lang_param.search("milk", replacements: { 'lang' => 'fr' })
|
229
|
+
lod_lang_param.search("milk", request_header: { replacements: { 'lang' => 'fr' } })
|
230
230
|
end
|
231
231
|
it "is correctly parsed" do
|
232
232
|
expect(results.first[:label]).to eq('Babeurre (délicieux)')
|
@@ -28,14 +28,14 @@ describe Qa::Authorities::Loc do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
context "for searching" do
|
31
|
-
let(:url) { '
|
31
|
+
let(:url) { 'https://id.loc.gov/search/?q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects&format=json' }
|
32
32
|
it "returns a url" do
|
33
33
|
expect(authority.build_query_url("foo")).to eq(url)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
context "for returning single terms" do
|
38
|
-
let(:url) { "
|
38
|
+
let(:url) { "https://id.loc.gov/authorities/subjects/sh2002003586.json" }
|
39
39
|
it "returns a url with an authority and id" do
|
40
40
|
expect(authority.find_url("sh2002003586")).to eq(url)
|
41
41
|
end
|
@@ -49,15 +49,15 @@ describe Qa::Authorities::Loc do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
before do
|
52
|
-
stub_request(:get, "
|
52
|
+
stub_request(:get, "https://id.loc.gov/search/?format=json&q=cs:http://id.loc.gov/authorities/subjects")
|
53
53
|
.with(headers: { 'Accept' => 'application/json' })
|
54
54
|
.to_return(status: 200, body: "")
|
55
55
|
end
|
56
56
|
|
57
57
|
context "with flat params encoded" do
|
58
|
-
let(:url) { '
|
58
|
+
let(:url) { 'https://id.loc.gov/search/?q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects&format=json' }
|
59
59
|
it "returns a response" do
|
60
|
-
flat_params_url = "
|
60
|
+
flat_params_url = "https://id.loc.gov/search/?format=json&q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects"
|
61
61
|
expect(subject.env.url.to_s).to eq(flat_params_url)
|
62
62
|
end
|
63
63
|
end
|
@@ -66,7 +66,7 @@ describe Qa::Authorities::Loc do
|
|
66
66
|
describe "#search" do
|
67
67
|
context "any LOC authorities" do
|
68
68
|
let :authority do
|
69
|
-
stub_request(:get, "
|
69
|
+
stub_request(:get, "https://id.loc.gov/search/?format=json&q=s&q=cs:http://id.loc.gov/vocabulary/geographicAreas")
|
70
70
|
.with(headers: { 'Accept' => 'application/json' })
|
71
71
|
.to_return(body: webmock_fixture("loc-response.txt"), status: 200)
|
72
72
|
described_class.subauthority_for("geographicAreas")
|
@@ -95,7 +95,7 @@ describe Qa::Authorities::Loc do
|
|
95
95
|
|
96
96
|
context "subject terms" do
|
97
97
|
let :results do
|
98
|
-
stub_request(:get, "
|
98
|
+
stub_request(:get, "https://id.loc.gov/search/?format=json&q=History--&q=cs:http://id.loc.gov/authorities/subjects")
|
99
99
|
.with(headers: { 'Accept' => 'application/json' })
|
100
100
|
.to_return(body: webmock_fixture("loc-subjects-response.txt"), status: 200)
|
101
101
|
described_class.subauthority_for("subjects").search("History--")
|
@@ -111,7 +111,7 @@ describe Qa::Authorities::Loc do
|
|
111
111
|
|
112
112
|
context "name terms" do
|
113
113
|
let :results do
|
114
|
-
stub_request(:get, "
|
114
|
+
stub_request(:get, "https://id.loc.gov/search/?format=json&q=Berry&q=cs:http://id.loc.gov/authorities/names")
|
115
115
|
.with(headers: { 'Accept' => 'application/json' })
|
116
116
|
.to_return(body: webmock_fixture("loc-names-response.txt"), status: 200)
|
117
117
|
described_class.subauthority_for("names").search("Berry")
|
@@ -125,7 +125,7 @@ describe Qa::Authorities::Loc do
|
|
125
125
|
describe "#find" do
|
126
126
|
context "using a subject id" do
|
127
127
|
let :results do
|
128
|
-
stub_request(:get, "
|
128
|
+
stub_request(:get, "https://id.loc.gov/authorities/subjects/sh2002003586.json")
|
129
129
|
.with(headers: { 'Accept' => 'application/json' })
|
130
130
|
.to_return(status: 200, body: webmock_fixture("loc-subject-find-response.txt"), headers: {})
|
131
131
|
described_class.subauthority_for("subjects").find("sh2002003586")
|
@@ -14,13 +14,19 @@ RSpec.describe Qa::LinkedData::AuthorityUrlService do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '.build_url' do
|
17
|
+
let(:request_header) do
|
18
|
+
{
|
19
|
+
subauthority: subauthority,
|
20
|
+
replacements: substitutions
|
21
|
+
}
|
22
|
+
end
|
17
23
|
context 'when authority is not registered' do
|
18
24
|
let(:authority) { :BAD_AUTHORITY }
|
19
25
|
|
20
26
|
it 'raises error' do
|
21
27
|
expected_error = Qa::InvalidLinkedDataAuthority
|
22
28
|
expected_error_message = "Unable to initialize linked data authority 'BAD_AUTHORITY'"
|
23
|
-
expect { described_class.build_url(action_config: action_config,
|
29
|
+
expect { described_class.build_url(action_config: action_config, action: action, action_request: action_request, request_header: request_header) }
|
24
30
|
.to raise_error(expected_error, expected_error_message)
|
25
31
|
end
|
26
32
|
end
|
@@ -33,7 +39,7 @@ RSpec.describe Qa::LinkedData::AuthorityUrlService do
|
|
33
39
|
skip "Pending better handling of unsupported subauthorities"
|
34
40
|
expected_error = Qa::InvalidLinkedDataAuthority
|
35
41
|
expected_error_message = "Unable to initialize linked data sub-authority BAD_SUBAUTHORITY"
|
36
|
-
expect { described_class.build_url(action_config: action_config,
|
42
|
+
expect { described_class.build_url(action_config: action_config, action: action, action_request: action_request, request_header: request_header) }
|
37
43
|
.to raise_error(expected_error, expected_error_message)
|
38
44
|
end
|
39
45
|
end
|
@@ -44,7 +50,7 @@ RSpec.describe Qa::LinkedData::AuthorityUrlService do
|
|
44
50
|
it 'raises error' do
|
45
51
|
expected_error = Qa::UnsupportedAction
|
46
52
|
expected_error_message = "BAD_ACTION Not Supported - Action must be one of the supported actions (e.g. :term, :search)"
|
47
|
-
expect { described_class.build_url(action_config: action_config,
|
53
|
+
expect { described_class.build_url(action_config: action_config, action: action, action_request: action_request, request_header: request_header) }
|
48
54
|
.to raise_error(expected_error, expected_error_message)
|
49
55
|
end
|
50
56
|
end
|
@@ -55,16 +61,16 @@ RSpec.describe Qa::LinkedData::AuthorityUrlService do
|
|
55
61
|
it 'raises error' do
|
56
62
|
expected_error = Qa::IriTemplate::MissingParameter
|
57
63
|
expected_error_message = "query is required, but missing"
|
58
|
-
expect { described_class.build_url(action_config: action_config,
|
64
|
+
expect { described_class.build_url(action_config: action_config, action: action, action_request: action_request, request_header: request_header) }
|
59
65
|
.to raise_error(expected_error, expected_error_message)
|
60
66
|
end
|
61
67
|
end
|
62
68
|
|
63
|
-
subject do
|
64
|
-
described_class.build_url(action_config: action_config, subauthority: subauthority, action: action, action_request: action_request, substitutions: substitutions)
|
65
|
-
end
|
66
|
-
|
67
69
|
context 'when no errors' do
|
70
|
+
subject do
|
71
|
+
described_class.build_url(action_config: action_config, action: action, action_request: action_request, request_header: request_header)
|
72
|
+
end
|
73
|
+
|
68
74
|
context 'and performing search action' do
|
69
75
|
context 'and all substitutions specified' do
|
70
76
|
let(:substitutions) do
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Qa::LinkedData::RequestHeaderService do
|
4
|
+
let(:request) { double }
|
5
|
+
|
6
|
+
describe '#search_header' do
|
7
|
+
context 'when optional params are defined' do
|
8
|
+
let(:search_params) do
|
9
|
+
{
|
10
|
+
'subauthority' => 'person',
|
11
|
+
'lang' => 'sp',
|
12
|
+
'maxRecords' => '4',
|
13
|
+
'context' => 'true',
|
14
|
+
'performance_data' => 'true'
|
15
|
+
}.with_indifferent_access
|
16
|
+
end
|
17
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => 'de') }
|
18
|
+
|
19
|
+
it 'uses passed in params' do
|
20
|
+
expected_results =
|
21
|
+
{
|
22
|
+
context: true,
|
23
|
+
performance_data: true,
|
24
|
+
replacements: { 'maxRecords' => '4' },
|
25
|
+
subauthority: 'person',
|
26
|
+
user_language: ['sp']
|
27
|
+
}
|
28
|
+
expect(described_class.new(request, search_params).search_header).to eq expected_results
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when none of the optional params are defined' do
|
33
|
+
context 'and request does not define language' do
|
34
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => nil) }
|
35
|
+
it 'returns defaults' do
|
36
|
+
expected_results =
|
37
|
+
{
|
38
|
+
context: false,
|
39
|
+
performance_data: false,
|
40
|
+
replacements: {},
|
41
|
+
subauthority: nil,
|
42
|
+
user_language: nil
|
43
|
+
}
|
44
|
+
expect(described_class.new(request, {}).search_header).to eq expected_results
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'and request does define language' do
|
49
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => 'de') }
|
50
|
+
it 'returns defaults with language set to request language' do
|
51
|
+
expected_results =
|
52
|
+
{
|
53
|
+
context: false,
|
54
|
+
performance_data: false,
|
55
|
+
replacements: {},
|
56
|
+
subauthority: nil,
|
57
|
+
user_language: ['de']
|
58
|
+
}
|
59
|
+
expect(described_class.new(request, {}).search_header).to eq expected_results
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#fetch_header' do
|
66
|
+
context 'when optional params are defined' do
|
67
|
+
let(:fetch_params) do
|
68
|
+
{
|
69
|
+
'subauthority' => 'person',
|
70
|
+
'lang' => 'sp',
|
71
|
+
'extra' => 'data',
|
72
|
+
'even' => 'more data',
|
73
|
+
'format' => 'n3',
|
74
|
+
'performance_data' => 'true'
|
75
|
+
}.with_indifferent_access
|
76
|
+
end
|
77
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => 'de') }
|
78
|
+
|
79
|
+
it 'uses passed in params' do
|
80
|
+
expected_results =
|
81
|
+
{
|
82
|
+
format: 'n3',
|
83
|
+
performance_data: true,
|
84
|
+
replacements: { 'extra' => 'data', 'even' => 'more data' },
|
85
|
+
subauthority: 'person',
|
86
|
+
user_language: ['sp']
|
87
|
+
}
|
88
|
+
expect(described_class.new(request, fetch_params).fetch_header).to eq expected_results
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when none of the optional params are defined' do
|
93
|
+
context 'and request does not define language' do
|
94
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => nil) }
|
95
|
+
it 'returns defaults' do
|
96
|
+
expected_results =
|
97
|
+
{
|
98
|
+
format: 'json',
|
99
|
+
performance_data: false,
|
100
|
+
replacements: {},
|
101
|
+
subauthority: nil,
|
102
|
+
user_language: nil
|
103
|
+
}
|
104
|
+
expect(described_class.new(request, {}).fetch_header).to eq expected_results
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'and request does define language' do
|
109
|
+
before { allow(request).to receive(:env).and_return('HTTP_ACCEPT_LANGUAGE' => 'de') }
|
110
|
+
it 'returns defaults with language set to request language' do
|
111
|
+
expected_results =
|
112
|
+
{
|
113
|
+
format: 'json',
|
114
|
+
performance_data: false,
|
115
|
+
replacements: {},
|
116
|
+
subauthority: nil,
|
117
|
+
user_language: ['de']
|
118
|
+
}
|
119
|
+
expect(described_class.new(request, {}).fetch_header).to eq expected_results
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Anderson
|
@@ -13,10 +13,10 @@ authors:
|
|
13
13
|
- Mike Stroming
|
14
14
|
- Adam Wead
|
15
15
|
- E. Lynette Rayle
|
16
|
-
autorequire:
|
16
|
+
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date:
|
19
|
+
date: 2020-08-14 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: activerecord-import
|
@@ -322,6 +322,7 @@ files:
|
|
322
322
|
- app/services/qa/linked_data/mapper/graph_predicate_mapper_service.rb
|
323
323
|
- app/services/qa/linked_data/mapper/search_results_mapper_service.rb
|
324
324
|
- app/services/qa/linked_data/mapper/term_results_mapper_service.rb
|
325
|
+
- app/services/qa/linked_data/request_header_service.rb
|
325
326
|
- app/views/layouts/qa/application.html.erb
|
326
327
|
- config/authorities.yml
|
327
328
|
- config/authorities/linked_data/loc.json
|
@@ -555,6 +556,7 @@ files:
|
|
555
556
|
- spec/services/linked_data/mapper/graph_predicate_mapper_service_spec.rb
|
556
557
|
- spec/services/linked_data/mapper/search_results_mapper_service_spec.rb
|
557
558
|
- spec/services/linked_data/mapper/term_results_mapper_service_spec.rb
|
559
|
+
- spec/services/linked_data/request_header_service_spec.rb
|
558
560
|
- spec/spec_helper.rb
|
559
561
|
- spec/support/matchers/include_hash.rb
|
560
562
|
- spec/test_app_templates/Gemfile.extra
|
@@ -563,7 +565,7 @@ homepage: https://github.com/projecthydra/questioning_authority
|
|
563
565
|
licenses:
|
564
566
|
- APACHE-2
|
565
567
|
metadata: {}
|
566
|
-
post_install_message:
|
568
|
+
post_install_message:
|
567
569
|
rdoc_options: []
|
568
570
|
require_paths:
|
569
571
|
- lib
|
@@ -578,9 +580,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
578
580
|
- !ruby/object:Gem::Version
|
579
581
|
version: '0'
|
580
582
|
requirements: []
|
581
|
-
|
582
|
-
|
583
|
-
signing_key:
|
583
|
+
rubygems_version: 3.0.8
|
584
|
+
signing_key:
|
584
585
|
specification_version: 4
|
585
586
|
summary: You should question your authorities.
|
586
587
|
test_files:
|
@@ -711,6 +712,7 @@ test_files:
|
|
711
712
|
- spec/routing/route_spec.rb
|
712
713
|
- spec/controllers/terms_controller_spec.rb
|
713
714
|
- spec/controllers/linked_data_terms_controller_spec.rb
|
715
|
+
- spec/services/linked_data/request_header_service_spec.rb
|
714
716
|
- spec/services/linked_data/authority_service_spec.rb
|
715
717
|
- spec/services/linked_data/ldpath_service_spec.rb
|
716
718
|
- spec/services/linked_data/graph_service_spec.rb
|