qa 2.0.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +54 -6
- data/app/controllers/qa/application_controller.rb +24 -0
- data/app/controllers/qa/linked_data_terms_controller.rb +116 -51
- data/app/controllers/qa/terms_controller.rb +7 -2
- data/app/models/qa/mesh_tree.rb +5 -9
- data/app/models/qa/subject_mesh_term.rb +2 -7
- data/config/authorities/linked_data/agrovoc.json +8 -1
- data/config/initializers/linked_data_authorities.rb +1 -17
- data/config/routes.rb +11 -0
- data/lib/generators/qa/apidoc/USAGE +11 -0
- data/lib/generators/qa/apidoc/apidoc_generator.rb +22 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/apidoc.json +1322 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/favicon-16x16.png +0 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/favicon-32x32.png +0 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/index.html +61 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/oauth2-redirect.html +67 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-bundle.js +93 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-bundle.js.map +1 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-standalone-preset.js +14 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui-standalone-preset.js.map +1 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.css +3 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.css.map +1 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.js +9 -0
- data/lib/generators/qa/apidoc/templates/public/qa/apidoc/swagger-ui.js.map +1 -0
- data/lib/generators/qa/install/install_generator.rb +11 -0
- data/lib/generators/qa/install/templates/config/initializers/qa.rb +13 -0
- data/lib/generators/qa/local/tables/mysql/mysql_generator.rb +1 -1
- data/lib/generators/qa/local/tables/tables_generator.rb +1 -1
- data/lib/qa.rb +16 -0
- data/lib/qa/authorities/assign_fast_subauthority.rb +3 -3
- data/lib/qa/authorities/getty/aat.rb +13 -6
- data/lib/qa/authorities/getty/tgn.rb +11 -22
- data/lib/qa/authorities/getty/ulan.rb +13 -16
- data/lib/qa/authorities/linked_data.rb +1 -0
- data/lib/qa/authorities/linked_data/authority_service.rb +47 -0
- data/lib/qa/authorities/linked_data/config.rb +9 -3
- data/lib/qa/authorities/linked_data/config/search_config.rb +16 -2
- data/lib/qa/authorities/linked_data/config/term_config.rb +17 -3
- data/lib/qa/authorities/linked_data/find_term.rb +4 -3
- data/lib/qa/authorities/linked_data/generic_authority.rb +8 -1
- data/lib/qa/authorities/linked_data/rdf_helper.rb +15 -0
- data/lib/qa/authorities/linked_data/search_query.rb +19 -3
- data/lib/qa/authorities/loc/generic_authority.rb +2 -2
- data/lib/qa/authorities/loc_subauthority.rb +2 -2
- data/lib/qa/authorities/local.rb +2 -4
- data/lib/qa/authorities/local/file_based_authority.rb +1 -1
- data/lib/qa/authorities/local/mysql_table_based_authority.rb +11 -2
- data/lib/qa/authorities/local/table_based_authority.rb +2 -1
- data/lib/qa/authorities/mesh_tools/mesh_data_parser.rb +1 -1
- data/lib/qa/authorities/mesh_tools/mesh_importer.rb +1 -1
- data/lib/qa/authorities/oclcts/generic_oclc_authority.rb +1 -3
- data/lib/qa/configuration.rb +34 -0
- data/lib/qa/version.rb +1 -1
- data/lib/tasks/mesh.rake +3 -3
- data/spec/controllers/linked_data_terms_controller_spec.rb +247 -18
- data/spec/controllers/terms_controller_spec.rb +87 -12
- data/spec/fixtures/authorities/linked_data/lod_encoding_config.json +91 -0
- data/spec/fixtures/authorities/linked_data/lod_term_id_param_config.json +27 -0
- data/spec/fixtures/authorities/linked_data/lod_term_uri_param_config.json +27 -0
- data/spec/fixtures/{lexvo_snippet.rdf → lexvo_snippet.rdf.xml} +1 -0
- data/spec/lib/authorities/assign_fast_spec.rb +3 -1
- data/spec/lib/authorities/file_based_authority_spec.rb +19 -11
- data/spec/lib/authorities/geonames_spec.rb +3 -3
- data/spec/lib/authorities/getty/aat_spec.rb +14 -8
- data/spec/lib/authorities/getty/tgn_spec.rb +8 -15
- data/spec/lib/authorities/getty/ulan_spec.rb +8 -6
- data/spec/lib/authorities/getty_spec.rb +2 -1
- data/spec/lib/authorities/linked_data/authority_service_spec.rb +47 -0
- data/spec/lib/authorities/linked_data/generic_authority_spec.rb +56 -14
- data/spec/lib/authorities/linked_data/search_config_spec.rb +33 -19
- data/spec/lib/authorities/linked_data/search_query_spec.rb +67 -15
- data/spec/lib/authorities/linked_data/term_config_spec.rb +34 -20
- data/spec/lib/authorities/loc_spec.rb +9 -9
- data/spec/lib/authorities/local_spec.rb +7 -8
- data/spec/lib/authorities/oclcts_spec.rb +27 -20
- data/spec/lib/authorities/table_based_authority_spec.rb +5 -3
- data/spec/lib/authorities_loc_subauthorities.rb +2 -2
- data/spec/lib/configuration_spec.rb +58 -0
- data/spec/lib/mesh_data_parser_spec.rb +2 -0
- data/spec/lib/services/rdf_authority_parser_spec.rb +1 -1
- data/spec/lib/tasks/mesh.rake_spec.rb +13 -12
- data/spec/models/subject_mesh_term_spec.rb +2 -0
- data/spec/requests/cors_headers_spec.rb +118 -0
- data/spec/spec_helper.rb +2 -2
- 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
|
-
|
19
|
-
|
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 =
|
23
|
-
ex += ")"
|
21
|
+
ex = "(#{clauses.join(' && ')})"
|
24
22
|
else
|
25
|
-
ex =
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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)
|
@@ -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 ||=
|
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.
|
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 [
|
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.
|
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
|
-
|
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
|
-
"
|
29
|
+
"https://id.loc.gov/search/?q=#{escaped_query}&q=#{authority_fragment}&format=json"
|
30
30
|
end
|
31
31
|
|
32
32
|
def find(id)
|
@@ -34,7 +34,7 @@ module Qa::Authorities
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def find_url(id)
|
37
|
-
"
|
37
|
+
"https://id.loc.gov/authorities/#{@subauthority}/#{id}.json"
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
@@ -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",
|
data/lib/qa/authorities/local.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|