qa 2.0.0 → 2.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.
Files changed (86) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +54 -6
  3. data/app/controllers/qa/application_controller.rb +24 -0
  4. data/app/controllers/qa/linked_data_terms_controller.rb +116 -51
  5. data/app/controllers/qa/terms_controller.rb +7 -2
  6. data/app/models/qa/mesh_tree.rb +5 -9
  7. data/app/models/qa/subject_mesh_term.rb +2 -7
  8. data/config/authorities/linked_data/agrovoc.json +8 -1
  9. data/config/initializers/linked_data_authorities.rb +1 -17
  10. data/config/routes.rb +11 -0
  11. data/lib/generators/qa/apidoc/USAGE +11 -0
  12. data/lib/generators/qa/apidoc/apidoc_generator.rb +22 -0
  13. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/apidoc.json +1322 -0
  14. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/favicon-16x16.png +0 -0
  15. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/favicon-32x32.png +0 -0
  16. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/index.html +61 -0
  17. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/oauth2-redirect.html +67 -0
  18. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-bundle.js +93 -0
  19. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-bundle.js.map +1 -0
  20. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-standalone-preset.js +14 -0
  21. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-standalone-preset.js.map +1 -0
  22. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.css +3 -0
  23. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.css.map +1 -0
  24. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.js +9 -0
  25. data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.js.map +1 -0
  26. data/lib/generators/qa/install/install_generator.rb +11 -0
  27. data/lib/generators/qa/install/templates/config/initializers/qa.rb +13 -0
  28. data/lib/generators/qa/local/tables/mysql/mysql_generator.rb +1 -1
  29. data/lib/generators/qa/local/tables/tables_generator.rb +1 -1
  30. data/lib/qa.rb +16 -0
  31. data/lib/qa/authorities/assign_fast_subauthority.rb +3 -3
  32. data/lib/qa/authorities/getty/aat.rb +13 -6
  33. data/lib/qa/authorities/getty/tgn.rb +11 -22
  34. data/lib/qa/authorities/getty/ulan.rb +13 -16
  35. data/lib/qa/authorities/linked_data.rb +1 -0
  36. data/lib/qa/authorities/linked_data/authority_service.rb +47 -0
  37. data/lib/qa/authorities/linked_data/config.rb +9 -3
  38. data/lib/qa/authorities/linked_data/config/search_config.rb +16 -2
  39. data/lib/qa/authorities/linked_data/config/term_config.rb +17 -3
  40. data/lib/qa/authorities/linked_data/find_term.rb +4 -3
  41. data/lib/qa/authorities/linked_data/generic_authority.rb +8 -1
  42. data/lib/qa/authorities/linked_data/rdf_helper.rb +15 -0
  43. data/lib/qa/authorities/linked_data/search_query.rb +19 -3
  44. data/lib/qa/authorities/loc/generic_authority.rb +2 -2
  45. data/lib/qa/authorities/loc_subauthority.rb +2 -2
  46. data/lib/qa/authorities/local.rb +2 -4
  47. data/lib/qa/authorities/local/file_based_authority.rb +1 -1
  48. data/lib/qa/authorities/local/mysql_table_based_authority.rb +11 -2
  49. data/lib/qa/authorities/local/table_based_authority.rb +2 -1
  50. data/lib/qa/authorities/mesh_tools/mesh_data_parser.rb +1 -1
  51. data/lib/qa/authorities/mesh_tools/mesh_importer.rb +1 -1
  52. data/lib/qa/authorities/oclcts/generic_oclc_authority.rb +1 -3
  53. data/lib/qa/configuration.rb +34 -0
  54. data/lib/qa/version.rb +1 -1
  55. data/lib/tasks/mesh.rake +3 -3
  56. data/spec/controllers/linked_data_terms_controller_spec.rb +247 -18
  57. data/spec/controllers/terms_controller_spec.rb +87 -12
  58. data/spec/fixtures/authorities/linked_data/lod_encoding_config.json +91 -0
  59. data/spec/fixtures/authorities/linked_data/lod_term_id_param_config.json +27 -0
  60. data/spec/fixtures/authorities/linked_data/lod_term_uri_param_config.json +27 -0
  61. data/spec/fixtures/{lexvo_snippet.rdf → lexvo_snippet.rdf.xml} +1 -0
  62. data/spec/lib/authorities/assign_fast_spec.rb +3 -1
  63. data/spec/lib/authorities/file_based_authority_spec.rb +19 -11
  64. data/spec/lib/authorities/geonames_spec.rb +3 -3
  65. data/spec/lib/authorities/getty/aat_spec.rb +14 -8
  66. data/spec/lib/authorities/getty/tgn_spec.rb +8 -15
  67. data/spec/lib/authorities/getty/ulan_spec.rb +8 -6
  68. data/spec/lib/authorities/getty_spec.rb +2 -1
  69. data/spec/lib/authorities/linked_data/authority_service_spec.rb +47 -0
  70. data/spec/lib/authorities/linked_data/generic_authority_spec.rb +56 -14
  71. data/spec/lib/authorities/linked_data/search_config_spec.rb +33 -19
  72. data/spec/lib/authorities/linked_data/search_query_spec.rb +67 -15
  73. data/spec/lib/authorities/linked_data/term_config_spec.rb +34 -20
  74. data/spec/lib/authorities/loc_spec.rb +9 -9
  75. data/spec/lib/authorities/local_spec.rb +7 -8
  76. data/spec/lib/authorities/oclcts_spec.rb +27 -20
  77. data/spec/lib/authorities/table_based_authority_spec.rb +5 -3
  78. data/spec/lib/authorities_loc_subauthorities.rb +2 -2
  79. data/spec/lib/configuration_spec.rb +58 -0
  80. data/spec/lib/mesh_data_parser_spec.rb +2 -0
  81. data/spec/lib/services/rdf_authority_parser_spec.rb +1 -1
  82. data/spec/lib/tasks/mesh.rake_spec.rb +13 -12
  83. data/spec/models/subject_mesh_term_spec.rb +2 -0
  84. data/spec/requests/cors_headers_spec.rb +118 -0
  85. data/spec/spec_helper.rb +2 -2
  86. metadata +167 -137
@@ -11,29 +11,26 @@ module Qa::Authorities
11
11
  "http://vocab.getty.edu/sparql.json?query=#{URI.escape(sparql(q)).gsub('&', '%26')}&_implicit=false&implicit=true&_equivalent=false&_form=%2Fsparql"
12
12
  end
13
13
 
14
- def sparql(q)
14
+ def sparql(q) # rubocop:disable Metrics/MethodLength
15
15
  search = untaint(q)
16
16
  # if more than one term is supplied, check both preferred and alt labels
17
17
  if search.include?(' ')
18
- ex = "("
19
- search.split(' ').each do |i|
20
- ex += "regex(CONCAT(?name, ' ', ?alt), \"#{i}\",\"i\" ) && "
18
+ clauses = search.split(' ').collect do |i|
19
+ %((regex(?name, "#{i}", "i") || regex(?alt, "#{i}", "i")))
21
20
  end
22
- ex = ex[0..ex.length - 4]
23
- ex += ")"
21
+ ex = "(#{clauses.join(' && ')})"
24
22
  else
25
- ex = "regex(?name, \"#{search}\", \"i\")"
23
+ ex = %(regex(?name, "#{search}", "i"))
26
24
  end
27
25
  # The full text index matches on fields besides the term, so we filter to ensure the match is in the term.
28
- sparql = "SELECT DISTINCT ?s ?name ?bio {
29
- ?s a skos:Concept; luc:term \"#{search}\";
30
- skos:inScheme <http://vocab.getty.edu/ulan/> ;
31
- gvp:prefLabelGVP [skosxl:literalForm ?name] ;
32
- foaf:focus/gvp:biographyPreferred [schema:description ?bio] ;
33
- skos:altLabel ?alt .
34
- FILTER #{ex} .
35
- } ORDER BY ?name"
36
- sparql
26
+ %(SELECT DISTINCT ?s ?name ?bio {
27
+ ?s a skos:Concept; luc:term "#{search}";
28
+ skos:inScheme <http://vocab.getty.edu/ulan/> ;
29
+ gvp:prefLabelGVP [skosxl:literalForm ?name] ;
30
+ foaf:focus/gvp:biographyPreferred [schema:description ?bio] ;
31
+ skos:altLabel ?alt .
32
+ FILTER #{ex} .
33
+ } ORDER BY ?name).gsub(/[\s\n]+/, " ")
37
34
  end
38
35
 
39
36
  def untaint(q)
@@ -3,6 +3,7 @@ module Qa::Authorities
3
3
  extend ActiveSupport::Autoload
4
4
  autoload :GenericAuthority
5
5
  autoload :RdfHelper
6
+ autoload :AuthorityService
6
7
  autoload :SearchQuery
7
8
  autoload :FindTerm
8
9
  autoload :Config
@@ -0,0 +1,47 @@
1
+ # This module has the primary QA search method. It also includes methods to process the linked data results and convert
2
+ # them into the expected QA json results format.
3
+ module Qa::Authorities
4
+ module LinkedData
5
+ class AuthorityService
6
+ # Load or reload the linked data configuration files
7
+ def self.load_authorities
8
+ auth_cfg = {}
9
+ # load QA configured linked data authorities
10
+ Dir[File.join(Qa::Engine.root, 'config', 'authorities', 'linked_data', '*.json')].each do |fn|
11
+ auth = File.basename(fn, '.json').upcase.to_sym
12
+ json = File.read(File.expand_path(fn, __FILE__))
13
+ cfg = JSON.parse(json).deep_symbolize_keys
14
+ auth_cfg[auth] = cfg
15
+ end
16
+
17
+ # load app configured linked data authorities and overrides
18
+ Dir[Rails.root.join('config', 'authorities', 'linked_data', '*.json')].each do |fn|
19
+ auth = File.basename(fn, '.json').upcase.to_sym
20
+ json = File.read(File.expand_path(fn, __FILE__))
21
+ cfg = JSON.parse(json).deep_symbolize_keys
22
+ auth_cfg[auth] = cfg
23
+ end
24
+ Qa.config.linked_data_authority_configs = auth_cfg
25
+ end
26
+
27
+ # Get the list of names of the loaded authorities
28
+ # @return [Array<String>] all loaded authority configurations
29
+ def self.authority_configs
30
+ Qa.config.linked_data_authority_configs
31
+ end
32
+
33
+ # Get the configuration for an authority
34
+ # @param [String] name of the authority
35
+ # @return [Array<String>] configuration for the specified authority
36
+ def self.authority_config(authname)
37
+ authority_configs[authname]
38
+ end
39
+
40
+ # Get the list of names of the loaded authorities
41
+ # @return [Array<String>] names of the authority config files that are currently loaded
42
+ def self.authority_names
43
+ authority_configs.keys.sort
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,6 +1,7 @@
1
1
  require 'qa/authorities/linked_data/config/term_config'.freeze
2
2
  require 'qa/authorities/linked_data/config/search_config'.freeze
3
3
  require 'json'
4
+ require 'erb'
4
5
 
5
6
  # Provide attr_reader methods for linked data authority configurations. Some default configurations are provided for several
6
7
  # linked data authorities and can be found at /config/authorities/linked_data. You can add configurations for new authorities by
@@ -17,6 +18,10 @@ require 'json'
17
18
  module Qa::Authorities
18
19
  module LinkedData
19
20
  class Config
21
+ class << self
22
+ include ERB::Util
23
+ end
24
+
20
25
  attr_reader :authority_name
21
26
  attr_reader :authority_config
22
27
 
@@ -39,7 +44,7 @@ module Qa::Authorities
39
44
  # Return the full configuration for an authority
40
45
  # @return [String] the authority configuration
41
46
  def auth_config
42
- @authority_config ||= LINKED_DATA_AUTHORITIES_CONFIG[@authority_name]
47
+ @authority_config ||= Qa::Authorities::LinkedData::AuthorityService.authority_config(@authority_name)
43
48
  raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data authority '#{@authority_name}'" if @authority_config.nil?
44
49
  @authority_config
45
50
  end
@@ -56,7 +61,8 @@ module Qa::Authorities
56
61
  pred_uri
57
62
  end
58
63
 
59
- def self.replace_pattern(url, pattern, value)
64
+ def self.replace_pattern(url, pattern, value, encode = false)
65
+ value = url_encode(value).gsub(".", "%2E") if encode
60
66
  url.gsub("{?#{pattern}}", value)
61
67
  end
62
68
 
@@ -71,7 +77,7 @@ module Qa::Authorities
71
77
  config.each do |param_key, rep_pattern|
72
78
  s_param_key = param_key.to_s
73
79
  value = replacements[param_key] || replacements[s_param_key] || rep_pattern[:default]
74
- url = replace_pattern(url, param_key, value)
80
+ url = replace_pattern(url, param_key, value, rep_pattern[:encode])
75
81
  end
76
82
  url
77
83
  end
@@ -95,12 +95,26 @@ module Qa::Authorities
95
95
  search_config.fetch(:qa_replacement_patterns)
96
96
  end
97
97
 
98
+ # Should the replacement pattern be encoded?
99
+ # @return [Boolean] true, if the pattern should be encoded; otherwise, false
100
+ def qa_replacement_encoded?(pattern_key)
101
+ map_key = qa_replacement_patterns[pattern_key].to_sym
102
+ replacement_encoded? map_key
103
+ end
104
+
98
105
  # Are there replacement parameters configured for search query?
99
106
  # @return [True|False] true if there are replacement parameters configured for search query; otherwise, false
100
107
  def replacements?
101
108
  replacement_count.positive?
102
109
  end
103
110
 
111
+ # Should the replacement parameter be encoded?
112
+ # @return [True|False] true if the replacement parameter should be encoded; otherwise, false
113
+ def replacement_encoded?(map_key)
114
+ return false unless url_mappings[map_key].key? :encode
115
+ url_mappings[map_key][:encode]
116
+ end
117
+
104
118
  # Return the number of possible replacement values to make in the search URL
105
119
  # @return [Integer] the configured number of possible replacements in the search url
106
120
  def replacement_count
@@ -159,8 +173,8 @@ module Qa::Authorities
159
173
  # @return [String] the search encoded url
160
174
  def url_with_replacements(query, sub_auth = nil, search_replacements = {})
161
175
  return nil unless supports_search?
162
- sub_auth = sub_auth.to_sym if sub_auth.is_a? String
163
- url = Config.replace_pattern(url_template, qa_replacement_patterns[:query], query)
176
+ sub_auth = sub_auth.to_sym if sub_auth.present?
177
+ url = Config.replace_pattern(url_template, qa_replacement_patterns[:query], query, qa_replacement_encoded?(:query))
164
178
  url = Config.process_subauthority(url, subauthority_replacement_pattern, subauthorities, sub_auth) if subauthorities?
165
179
  url = Config.apply_replacements(url, replacements, search_replacements) if replacements?
166
180
  url
@@ -112,12 +112,26 @@ module Qa::Authorities
112
112
  Config.config_value(term_config, :qa_replacement_patterns)
113
113
  end
114
114
 
115
+ # Should the replacement pattern be encoded?
116
+ # @return [Boolean] true, if the pattern should be encoded; otherwise, false
117
+ def term_qa_replacement_encoded?(pattern_key)
118
+ map_key = term_qa_replacement_patterns[pattern_key].to_sym
119
+ term_replacement_encoded? map_key
120
+ end
121
+
115
122
  # Are there replacement parameters configured for term fetch?
116
- # @return [True|False] true if there are replacement parameters configured for term fetch; otherwise, false
123
+ # @return [Boolean] true if there are replacement parameters configured for term fetch; otherwise, false
117
124
  def term_replacements?
118
125
  term_replacement_count.positive?
119
126
  end
120
127
 
128
+ # Should the replacement parameter be encoded?
129
+ # @return [Boolean] true if the replacement parameter should be encoded; otherwise, false
130
+ def term_replacement_encoded?(map_key)
131
+ return false unless term_url_mappings[map_key].key? :encode
132
+ term_url_mappings[map_key][:encode]
133
+ end
134
+
121
135
  # Return the number of possible replacement values to make in the term URL
122
136
  # @return [Integer] the configured number of possible replacements in the term url
123
137
  def term_replacement_count
@@ -129,7 +143,7 @@ module Qa::Authorities
129
143
  def term_replacements
130
144
  return @term_replacements unless @term_replacements.nil?
131
145
  @term_replacements = {}
132
- @term_replacements = term_url_mappings.select { |k, _v| !term_qa_replacement_patterns.include?(k) } unless term_config.nil? || term_url_mappings.nil?
146
+ @term_replacements = term_url_mappings.select { |k, _v| !term_qa_replacement_patterns.value?(k.to_s) } unless term_config.nil? || term_url_mappings.nil?
133
147
  @term_replacements
134
148
  end
135
149
 
@@ -176,7 +190,7 @@ module Qa::Authorities
176
190
  def term_url_with_replacements(id, sub_auth = nil, replacements = {})
177
191
  return nil unless supports_term?
178
192
  sub_auth = sub_auth.to_sym if sub_auth.is_a? String
179
- url = Config.replace_pattern(term_url_template, term_qa_replacement_patterns[:term_id], id)
193
+ url = Config.replace_pattern(term_url_template, term_qa_replacement_patterns[:term_id], id, term_qa_replacement_encoded?(:term_id))
180
194
  url = Config.process_subauthority(url, term_subauthority_replacement_pattern, term_subauthorities, sub_auth) if term_subauthorities?
181
195
  url = Config.apply_replacements(url, term_replacements, replacements) if term_replacements?
182
196
  url
@@ -33,13 +33,14 @@ module Qa::Authorities
33
33
  # "http://schema.org/name":["Cornell University","Ithaca (N.Y.). Cornell University"],
34
34
  # "http://www.w3.org/2004/02/skos/core#altLabel":["Ithaca (N.Y.). Cornell University"],
35
35
  # "http://schema.org/sameAs":["http://id.loc.gov/authorities/names/n79021621","https://viaf.org/viaf/126293486"] } }
36
- def find(id, language: nil, replacements: {}, subauth: nil)
36
+ def find(id, language: nil, replacements: {}, subauth: nil, jsonld: false)
37
37
  raise Qa::InvalidLinkedDataAuthority, "Unable to initialize linked data term sub-authority #{subauth}" unless subauth.nil? || term_subauthority?(subauth)
38
38
  language ||= term_config.term_language
39
39
  url = term_config.term_url_with_replacements(id, subauth, replacements)
40
40
  Rails.logger.info "QA Linked Data term url: #{url}"
41
41
  graph = get_linked_data(url)
42
42
  return "{}" unless graph.size.positive?
43
+ return graph.dump(:jsonld, standard_prefixes: true) if jsonld
43
44
  parse_term_authority_response(id, graph, language)
44
45
  end
45
46
 
@@ -76,7 +77,7 @@ module Qa::Authorities
76
77
  preds
77
78
  end
78
79
 
79
- def consolidate_term_results(results)
80
+ def consolidate_term_results(results) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize # TODO: Explore a way to simplify
80
81
  consolidated_results = {}
81
82
  results.each do |statement|
82
83
  stmt_hash = statement.to_h
@@ -123,7 +124,7 @@ module Qa::Authorities
123
124
  json_results.first
124
125
  end
125
126
 
126
- def predicates_with_subject_uri(graph, expected_uri)
127
+ def predicates_with_subject_uri(graph, expected_uri) # rubocop:disable Metrics/MethodLength
127
128
  predicates_hash = {}
128
129
  graph.statements.each do |st|
129
130
  subj = st.subject.to_s
@@ -22,7 +22,13 @@ module Qa::Authorities
22
22
  @auth_config = Qa::Authorities::LinkedData::Config.new(auth_name)
23
23
  end
24
24
 
25
- include WebServiceBase
25
+ def reload_authorities
26
+ @authorities_service.load_authorities
27
+ end
28
+
29
+ def authorities_service
30
+ @authorities_service ||= Qa::Authorities::LinkedData::AuthorityService
31
+ end
26
32
 
27
33
  def search_service
28
34
  @search_service ||= Qa::Authorities::LinkedData::SearchQuery.new(search_config)
@@ -34,6 +40,7 @@ module Qa::Authorities
34
40
 
35
41
  delegate :search, to: :search_service
36
42
  delegate :find, to: :item_service
43
+ delegate :load_authorities, :authority_names, to: :authorities_service
37
44
 
38
45
  private
39
46
 
@@ -57,6 +57,10 @@ module Qa::Authorities
57
57
  msg[a..z]
58
58
  end
59
59
 
60
+ # Filter a graph to the specified languages
61
+ # @param [RDF::Graph] the graph to be filtered.
62
+ # @param [String | Symbol | Array<String|Symbol>] language for filtering graph (e.g. "en" or :en or ["en", "fr"] or [:en, :fr])
63
+ # @returns [RDF::Graph] graph of linked data filtered on the specified languages
60
64
  def filter_language(graph, language)
61
65
  language = normalize_language(language)
62
66
  return graph if language.nil?
@@ -66,6 +70,17 @@ module Qa::Authorities
66
70
  graph
67
71
  end
68
72
 
73
+ # Filter a graph to remove any statement with a blanknode for the subject
74
+ # @param [RDF::Graph] the graph to be filtered.
75
+ # @returns [RDF::Graph] graph of linked data with blanknodes removed
76
+ def filter_out_blanknodes(graph)
77
+ return graph if graph.subjects.blank?
78
+ graph.each do |st|
79
+ graph.delete(st) if st.subject.anonymous?
80
+ end
81
+ graph
82
+ end
83
+
69
84
  def normalize_language(language)
70
85
  language = [language.to_sym] if language.is_a? String
71
86
  language = [language] if language.is_a? Symbol
@@ -37,6 +37,7 @@ module Qa::Authorities
37
37
 
38
38
  def parse_search_authority_response(graph, language)
39
39
  graph = filter_language(graph, language) unless language.nil?
40
+ graph = filter_out_blanknodes(graph)
40
41
  results = extract_preds(graph, preds_for_search)
41
42
  consolidated_results = consolidate_search_results(results)
42
43
  json_results = convert_search_to_json(consolidated_results)
@@ -61,7 +62,7 @@ module Qa::Authorities
61
62
  preds
62
63
  end
63
64
 
64
- def consolidate_search_results(results)
65
+ def consolidate_search_results(results) # rubocop:disable Metrics/MethodLength
65
66
  consolidated_results = {}
66
67
  return consolidated_results if results.nil? || !results.count.positive?
67
68
  results.each do |statement|
@@ -105,11 +106,14 @@ module Qa::Authorities
105
106
  lbl
106
107
  end
107
108
 
108
- def sort_search_results(json_results)
109
+ def sort_search_results(json_results) # rubocop:disable Metrics/MethodLength
109
110
  return json_results unless supports_sort?
110
111
  json_results.sort! do |a, b|
111
112
  cmp = sort_when_missing_sort_predicate(a, b)
112
- next unless cmp.nil?
113
+ next cmp unless cmp.nil?
114
+
115
+ cmp = numeric_sort(a, b)
116
+ next cmp unless cmp.nil?
113
117
 
114
118
  as = a[:sort].collect(&:downcase)
115
119
  bs = b[:sort].collect(&:downcase)
@@ -138,6 +142,18 @@ module Qa::Authorities
138
142
  return 1 if bs.size <= current_list_size # consider shorter b list of values lower then longer a list
139
143
  nil
140
144
  end
145
+
146
+ def numeric_sort(a, b)
147
+ return nil if a[:sort].size > 1
148
+ return nil if b[:sort].size > 1
149
+ return nil unless s_is_i? a[:sort][0]
150
+ return nil unless s_is_i? b[:sort][0]
151
+ Integer(a[:sort][0]) <=> Integer(b[:sort][0])
152
+ end
153
+
154
+ def s_is_i?(s)
155
+ /\A[-+]?\d+\z/ === s # rubocop:disable Style/CaseEquality
156
+ end
141
157
  end
142
158
  end
143
159
  end
@@ -26,7 +26,7 @@ module Qa::Authorities
26
26
  def build_query_url(q)
27
27
  escaped_query = URI.escape(q)
28
28
  authority_fragment = Loc.get_url_for_authority(subauthority) + URI.escape(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
@@ -18,7 +18,7 @@ module Qa::Authorities::LocSubauthority
18
18
  ]
19
19
  end
20
20
 
21
- def vocabularies
21
+ def vocabularies # rubocop:disable Metrics/MethodLength
22
22
  [
23
23
  "graphicMaterials",
24
24
  "organizations",
@@ -40,7 +40,7 @@ module Qa::Authorities::LocSubauthority
40
40
  ["edtf"]
41
41
  end
42
42
 
43
- def preservation
43
+ def preservation # rubocop:disable Metrics/MethodLength
44
44
  [
45
45
  "contentLocationType",
46
46
  "copyrightStatus",
@@ -20,15 +20,13 @@ module Qa::Authorities
20
20
  if config[:local_path].starts_with?(File::Separator)
21
21
  config[:local_path]
22
22
  else
23
- File.join(Rails.root, config[:local_path])
23
+ Rails.root.join(config[:local_path]).to_s # TODO: Rails.root.join returns class Pathname, which may be ok. Added to_s because of failing regression test.
24
24
  end
25
25
  end
26
26
 
27
27
  # Local sub-authorities are any YAML files in the subauthorities_path
28
28
  def names
29
- unless Dir.exist? subauthorities_path
30
- raise Qa::ConfigDirectoryNotFound, "There's no directory at #{subauthorities_path}. You must create it in order to use local authorities"
31
- end
29
+ raise Qa::ConfigDirectoryNotFound, "There's no directory at #{subauthorities_path}. You must create it in order to use local authorities" unless Dir.exist? subauthorities_path
32
30
  Dir.entries(subauthorities_path).map { |f| File.basename(f, ".yml") if f =~ /yml$/ }.compact
33
31
  end
34
32
 
@@ -25,7 +25,7 @@ module Qa::Authorities
25
25
  private
26
26
 
27
27
  def terms
28
- subauthority_hash = YAML.load(File.read(subauthority_filename))
28
+ subauthority_hash = YAML.load(File.read(subauthority_filename)) # rubocop:disable Security/YAMLLoad # TODO: Explore how to change this to safe_load. Many tests fail when making this change.
29
29
  terms = subauthority_hash.with_indifferent_access.fetch(:terms, [])
30
30
  normalize_terms(terms)
31
31
  end
@@ -5,8 +5,7 @@ module Qa
5
5
  self.table_index = "index_qa_local_authority_entries_on_lower_label_and_authority"
6
6
 
7
7
  def self.check_for_index
8
- conn = ActiveRecord::Base.connection
9
- if table_or_view_exists? && conn.index_name_exists?(table_name.to_sym, table_index, :default).blank?
8
+ if table_or_view_exists? && index_name_exists? # rubocop:disable Style/GuardClause
10
9
  Rails.logger.error "You've installed mysql local authority tables, but you haven't indexed the lower label. "
11
10
  "Rails doesn't support functional indexes in migrations, so we tried to execute it for you but something went wrong...\n" \
12
11
  "Make sure your table has a lower_label column, which is virtually created, and that the column is indexed." \
@@ -19,6 +18,16 @@ module Qa
19
18
  return [] if q.blank?
20
19
  output_set(base_relation.where('lower_label like ?', "#{q.downcase}%").limit(25))
21
20
  end
21
+
22
+ def self.index_name_exists?
23
+ conn = ActiveRecord::Base.connection
24
+ if ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MINOR >= 1
25
+ conn.index_name_exists?(table_name, table_index).blank?
26
+ else
27
+ conn.index_name_exists?(table_name, table_index, :default).blank?
28
+ end
29
+ end
30
+ private_class_method :index_name_exists?
22
31
  end
23
32
  end
24
33
  end