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