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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 01ad19bed0c7676d2a803cdf50f3edb8f3786f88
4
- data.tar.gz: 30f46f8326eabb8fc00e3e27dadd0f2d2c72d8fa
2
+ SHA256:
3
+ metadata.gz: 7e4ee1da3b72cee5194380a24b44e96793395d110cbe2234da55541da3f962c9
4
+ data.tar.gz: 27dffc56d77c9e583000c99823a31fe8c90f3591ea3de04935c4e476bda9d289
5
5
  SHA512:
6
- metadata.gz: 3ea728ae633c1a0f504f3d76ac7eb0bd1c353f35a2fdb174d3dcfa42a8798c5c18af88f1bef2d0224fe13b7b583a285f350e13ae78377d09b73b83c40c0505fc
7
- data.tar.gz: e11d1a74bc87fc1d93b1c5a543ac10a928f3d8c562762b0ecd1e801851f14e26190d69ea532d67d760631c02c120e5970f90ff901595392a4b69c3ebadddc352
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, Metrics/AbcSize
39
- terms = @authority.search(query, subauth: subauthority, language: language, replacements: replacement_params, context: context?, performance_data: performance_data?)
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, subauth: subauthority, language: language, replacements: replacement_params, format: format, performance_data: performance_data?)
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, subauth: subauthority, language: language, replacements: replacement_params, format: format, performance_data: performance_data?)
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 substitutions [Hash] variable-value pairs to substitute into the URL template (optional)
11
- # @param subauthority [String] name of a subauthority (optional)
12
- # @param language [Array<Symbol>] languages for filtering returned literals (optional)
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
- def build_url(action_config:, action:, action_request:, substitutions: {}, subauthority: nil, language: nil) # rubocop:disable Metrics/ParameterLists
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, substitutions, subauthority, language))
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, substitutions, subauthority, language) # rubocop:disable Metrics/ParameterLists
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, subauthority) if supports_subauthorities?(action_config) && subauthority.present?
31
- substitutions[action_language_variable(action_config)] = language_value(language) if supports_language_parameter?(action_config) && language.present?
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, subauthority)
49
- action_config.subauthorities[subauthority.to_sym]
50
- end
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(language)
61
- return nil if language.blank?
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
- # "uri": "https://api.discogs.com/releases/4212473",
106
- # "id": "4212473",
107
- # "label": "Frank Sinatra And The Modernaires - Sorry / Why Remind Me",
108
- # }
109
- # "context": {
110
- # "Image URL": [
111
- # "https://img.discogs.com/2e-YoNr0dvmMgbzEN0hjHD6X0sU=/fit-in/600x580/filters:strip_icc():format(jpeg):mode_rgb():quality(90)/discogs-images/R-4212473-1358693671-5430.jpeg.jpg"
112
- # ],
113
- # "Year": [
114
- # "1950"
115
- # ],
116
- # "Record Labels": [
117
- # "Columbia"
118
- # ],
119
- # "Formats": [
120
- # "Shellac",
121
- # "10\"",
122
- # "78 RPM"
123
- # ],
124
- # "Type": [
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
- "Year" => get_context_for_string(result['year']),
146
- "Record Labels" => get_context_for_array(result['label']),
147
- "Formats" => get_context_for_array(result['format']),
148
- "Type" => get_context_for_string(result['type']) }
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 [Symbol] (optional) language: language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
26
- # @param [Hash] (optional) replacements: replacement values with { pattern_name (defined in YAML config) => value }
27
- # @param [String] subauth: the subauthority from which to fetch the term
28
- # @return [Hash] json results
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: nil, jsonld: false, performance_data: false) # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
43
- # TODO: When jsonld parameter is removed, the format parameter should default to 'json'. Not making this change now for backward compatibility of the default for jsonld parameter.
44
- raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data term sub-authority #{subauth}" unless subauth.nil? || term_subauthority?(subauth)
45
- @language = language_service.preferred_language(user_language: language, authority_language: term_config.term_language)
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
- @performance_data = performance_data
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
- json = perform_normalization
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 = json.to_s.size if performance_data?
83
- Rails.logger.info("Time to convert data to json: #{normalize_time_s}s")
84
- json = append_performance_data(json) if performance_data?
85
- json
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 language [Symbol] (optional) language used to select literals when multi-language is supported (e.g. :en, :fr, etc.)
26
- # @param replacements [Hash] (optional) replacement values with { pattern_name (defined in YAML config) => value }
27
- # @param subauth [String] (optional) the subauthority to query
28
- # @param context [Boolean] (optional) true if context should be returned with the results; otherwise, false (default: false)
29
- # @param performance_data [Boolean] (optional) true if include_performance_data should be returned with the results; otherwise, false (default: false)
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
- raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data search sub-authority #{subauth}" unless subauth.nil? || subauthority?(subauth)
37
- @context = context
38
- @performance_data = performance_data
39
- @language = language_service.preferred_language(user_language: language, authority_language: search_config.language)
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 convert data to json: #{normalize_time_s}s")
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: @language, context_map: context_map)
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
- "http://id.loc.gov/search/?q=#{escaped_query}&q=#{authority_fragment}&format=json"
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
- "http://id.loc.gov/authorities/#{@subauthority}/#{id}.json"
37
+ "https://id.loc.gov/authorities/#{@subauthority}/#{id}.json"
38
38
  end
39
39
 
40
40
  private
@@ -1,3 +1,3 @@
1
1
  module Qa
2
- VERSION = "4.2.4".freeze
2
+ VERSION = "4.3.0".freeze
3
3
  end
@@ -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, "http://id.loc.gov/search/?format=json&q=Berry&q=cs:http://id.loc.gov/authorities/names")
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, "http://id.loc.gov/authorities/subjects/sh85077565.json")
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"]["Year"]).to eq ['2009']
280
- expect(results.first["context"]["Formats"][0]).to eq "Vinyl"
281
- expect(results.first["context"]["Record Labels"][1]).to eq "Universal Music Classics & Jazz"
282
- expect(results.first["context"]["Type"][0]).to eq "release"
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']["Year"]).to eq ['1966']
303
- expect(results.first['context']["Formats"][2]).to eq "45 RPM"
304
- expect(results.first["context"]["Type"][0]).to eq "master"
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', subauth: 'subjects') }
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', subauth: 'subjects') }
186
- let(:second_results) { lod_loc.find('sh 1234', subauth: 'subjects') }
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', subauth: 'subjects') }
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', subauth: 'subjects') }.to raise_error Qa::DataNormalizationError, "Unable to extract URI based on ID: 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', subauth: 'subjects') }
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', subauth: 'personal_name', replacements: { 'maximumRecords' => '3' }, performance_data: true)
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', subauth: 'personal_name', replacements: { 'maximumRecords' => '3' }, performance_data: false)
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', subauth: 'personal_name', replacements: { 'maximumRecords' => '3' })
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', subauth: 'personal_name', replacements: { 'maximumRecords' => '3' })
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', subauth: 'personal_name', replacements: { 'maximumRecords' => '3' })
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) { 'http://id.loc.gov/search/?q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects&format=json' }
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) { "http://id.loc.gov/authorities/subjects/sh2002003586.json" }
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, "http://id.loc.gov/search/?format=json&q=cs:http://id.loc.gov/authorities/subjects")
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) { 'http://id.loc.gov/search/?q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects&format=json' }
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 = "http://id.loc.gov/search/?format=json&q=foo&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fauthorities%2Fsubjects"
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, "http://id.loc.gov/search/?format=json&q=s&q=cs:http://id.loc.gov/vocabulary/geographicAreas")
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, "http://id.loc.gov/search/?format=json&q=History--&q=cs:http://id.loc.gov/authorities/subjects")
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, "http://id.loc.gov/search/?format=json&q=Berry&q=cs:http://id.loc.gov/authorities/names")
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, "http://id.loc.gov/authorities/subjects/sh2002003586.json")
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, subauthority: subauthority, action: action, action_request: action_request, substitutions: substitutions) }
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, subauthority: subauthority, action: action, action_request: action_request, substitutions: substitutions) }
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, subauthority: subauthority, action: action, action_request: action_request, substitutions: substitutions) }
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, subauthority: subauthority, action: action, action_request: action_request, substitutions: substitutions) }
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.2.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: 2019-10-17 00:00:00.000000000 Z
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
- rubyforge_project:
582
- rubygems_version: 2.6.14
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