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 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