blacklight 5.9.4 → 5.10.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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/VERSION +1 -1
  4. data/app/assets/stylesheets/blacklight/_facets.scss +11 -10
  5. data/app/helpers/blacklight/blacklight_helper_behavior.rb +14 -14
  6. data/app/helpers/blacklight/configuration_helper_behavior.rb +16 -10
  7. data/app/helpers/blacklight/facets_helper_behavior.rb +15 -14
  8. data/app/helpers/blacklight/url_helper_behavior.rb +1 -1
  9. data/app/models/bookmark.rb +1 -4
  10. data/app/models/search.rb +3 -6
  11. data/app/views/catalog/_facet_layout.html.erb +2 -2
  12. data/app/views/catalog/_facet_limit.html.erb +5 -3
  13. data/app/views/catalog/_facet_pivot.html.erb +4 -4
  14. data/app/views/catalog/_home_text.html.erb +8 -48
  15. data/app/views/catalog/_index_default.html.erb +3 -3
  16. data/app/views/catalog/_show_default.html.erb +3 -3
  17. data/app/views/catalog/_sms_form.html.erb +1 -1
  18. data/app/views/catalog/facet.html.erb +1 -1
  19. data/blacklight.gemspec +1 -1
  20. data/config/jetty.yml +0 -3
  21. data/config/locales/blacklight.de.yml +2 -0
  22. data/config/locales/blacklight.en.yml +2 -0
  23. data/config/locales/blacklight.es.yml +2 -0
  24. data/config/locales/blacklight.fr.yml +2 -0
  25. data/config/locales/blacklight.pt-BR.yml +2 -0
  26. data/lib/blacklight.rb +70 -26
  27. data/lib/blacklight/abstract_repository.rb +29 -0
  28. data/lib/blacklight/base.rb +7 -7
  29. data/lib/blacklight/bookmarks.rb +5 -5
  30. data/lib/blacklight/catalog.rb +34 -19
  31. data/lib/blacklight/catalog/search_context.rb +1 -1
  32. data/lib/blacklight/configuration.rb +112 -46
  33. data/lib/blacklight/configuration/facet_field.rb +9 -7
  34. data/lib/blacklight/configuration/field.rb +27 -0
  35. data/lib/blacklight/configuration/fields.rb +25 -20
  36. data/lib/blacklight/configuration/search_field.rb +6 -8
  37. data/lib/blacklight/configuration/solr_field.rb +3 -18
  38. data/lib/blacklight/configuration/sort_field.rb +6 -7
  39. data/lib/blacklight/document.rb +156 -0
  40. data/lib/blacklight/document/dublin_core.rb +41 -0
  41. data/lib/blacklight/document/email.rb +16 -0
  42. data/lib/blacklight/document/export.rb +107 -0
  43. data/lib/blacklight/document/extensions.rb +56 -0
  44. data/lib/blacklight/document/schema_org.rb +7 -0
  45. data/lib/blacklight/document/semantic_fields.rb +51 -0
  46. data/lib/blacklight/document/sms.rb +14 -0
  47. data/lib/blacklight/document_presenter.rb +3 -3
  48. data/lib/blacklight/exceptions.rb +9 -2
  49. data/lib/blacklight/facet.rb +21 -16
  50. data/lib/blacklight/request_builders.rb +60 -284
  51. data/lib/blacklight/routes.rb +1 -1
  52. data/lib/blacklight/search_builder.rb +130 -0
  53. data/lib/blacklight/search_helper.rb +316 -0
  54. data/lib/blacklight/solr.rb +1 -0
  55. data/lib/blacklight/solr/document.rb +4 -187
  56. data/lib/blacklight/solr/document/dublin_core.rb +3 -37
  57. data/lib/blacklight/solr/document/email.rb +4 -13
  58. data/lib/blacklight/solr/document/export.rb +3 -103
  59. data/lib/blacklight/solr/document/extensions.rb +4 -52
  60. data/lib/blacklight/solr/document/more_like_this.rb +1 -1
  61. data/lib/blacklight/solr/document/schema_org.rb +4 -4
  62. data/lib/blacklight/solr/document/sms.rb +4 -11
  63. data/lib/blacklight/solr/facet_paginator.rb +2 -2
  64. data/lib/blacklight/solr/search_builder.rb +264 -0
  65. data/lib/blacklight/solr_helper.rb +6 -261
  66. data/lib/blacklight/solr_repository.rb +30 -24
  67. data/lib/blacklight/solr_response.rb +3 -3
  68. data/lib/blacklight/user.rb +1 -2
  69. data/lib/blacklight/utils.rb +0 -23
  70. data/lib/generators/blacklight/controller_generator.rb +38 -0
  71. data/lib/generators/blacklight/document_generator.rb +20 -0
  72. data/lib/generators/blacklight/install_generator.rb +38 -39
  73. data/lib/generators/blacklight/models_generator.rb +2 -62
  74. data/lib/generators/blacklight/templates/catalog_controller.rb +3 -4
  75. data/lib/generators/blacklight/templates/config/{solr.yml → blacklight.yml} +3 -0
  76. data/lib/generators/blacklight/templates/config/jetty.yml +0 -3
  77. data/lib/generators/blacklight/templates/solr_document.rb +6 -6
  78. data/lib/generators/blacklight/test_support_generator.rb +1 -6
  79. data/lib/generators/blacklight/user_generator.rb +59 -0
  80. data/lib/railties/blacklight.rake +16 -7
  81. data/spec/controllers/catalog_controller_spec.rb +9 -15
  82. data/spec/features/facets_spec.rb +8 -0
  83. data/spec/helpers/configuration_helper_spec.rb +6 -13
  84. data/spec/helpers/facets_helper_spec.rb +3 -2
  85. data/spec/lib/blacklight/configuration_spec.rb +11 -38
  86. data/spec/lib/blacklight/{solr/document → document}/dublin_core_spec.rb +4 -4
  87. data/spec/lib/blacklight/{solr/document → document}/email_spec.rb +2 -2
  88. data/spec/lib/blacklight/{solr/document → document}/sms_spec.rb +2 -2
  89. data/spec/lib/blacklight/search_builder_spec.rb +145 -0
  90. data/spec/lib/blacklight/search_helper_spec.rb +775 -0
  91. data/spec/lib/blacklight/solr/document/more_like_this_spec.rb +1 -1
  92. data/spec/lib/blacklight/solr/search_builder_spec.rb +561 -0
  93. data/spec/lib/blacklight/solr_helper_spec.rb +5 -1291
  94. data/spec/lib/blacklight/solr_repository_spec.rb +13 -13
  95. data/spec/models/record_mailer_spec.rb +2 -2
  96. data/spec/spec_helper.rb +1 -0
  97. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  98. data/spec/views/catalog/_constraints.html.erb_spec.rb +1 -1
  99. data/spec/views/catalog/_paginate_compact.html.erb_spec.rb +2 -2
  100. data/spec/views/catalog/index.atom.builder_spec.rb +1 -1
  101. data/tasks/blacklight.rake +1 -1
  102. data/template.demo.rb +1 -1
  103. metadata +33 -45
  104. data/doc/Adding-new-document-actions.md +0 -94
  105. data/doc/Atom-Responses.md +0 -90
  106. data/doc/Blacklight-Add-ons.md +0 -23
  107. data/doc/Blacklight-configuration.md +0 -411
  108. data/doc/Blacklight-on-Heroku.md +0 -100
  109. data/doc/Blacklight-out-of-the-box.md +0 -47
  110. data/doc/Bookmarks.md +0 -1
  111. data/doc/Code4Lib-2014.md +0 -94
  112. data/doc/Configuration---Facet-Fields.md +0 -130
  113. data/doc/Configuration---Results-View.md +0 -224
  114. data/doc/Configuration---Solr-fields.md +0 -106
  115. data/doc/Configuring-and-Customizing-Blacklight.md +0 -257
  116. data/doc/Configuring-rails-routes.md +0 -13
  117. data/doc/Contributing-to-Blacklight.md +0 -43
  118. data/doc/Examples.md +0 -120
  119. data/doc/Extending-or-Modifying-Blacklight-Search-Behavior.md +0 -141
  120. data/doc/Home.md +0 -100
  121. data/doc/How-to-release-a-version.md +0 -45
  122. data/doc/Indexing-your-data-into-solr.md +0 -36
  123. data/doc/Internationalization.md +0 -32
  124. data/doc/JSON-API.md +0 -83
  125. data/doc/Pagination.md +0 -52
  126. data/doc/Providing-your-own-view-templates.md +0 -69
  127. data/doc/Quickstart.md +0 -153
  128. data/doc/README_SOLR.md +0 -245
  129. data/doc/Saved-Searches.md +0 -5
  130. data/doc/Solr-Configuration.md +0 -154
  131. data/doc/Sunspot-for-indexing.md +0 -46
  132. data/doc/Support.md +0 -33
  133. data/doc/Theming.md +0 -62
  134. data/doc/Understanding-Rails-and-Blacklight.md +0 -75
  135. data/doc/User-Authentication.md +0 -60
  136. data/doc/_Sidebar.md +0 -9
  137. data/doc/testing.md +0 -58
@@ -0,0 +1,7 @@
1
+ module Blacklight::Document::SchemaOrg
2
+
3
+ def itemtype
4
+ "http://schema.org/Thing"
5
+ end
6
+
7
+ end
@@ -0,0 +1,51 @@
1
+ module Blacklight::Document
2
+ module SemanticFields
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Returns array of hashes of registered extensions. Each hash
7
+ # has a :module_obj key and a :condition_proc key. Usually this
8
+ # method is only used internally in #apply_extensions, but if you
9
+
10
+ # Class-level method for accessing/setting semantic mappings
11
+ # for solr stored fields. Can be set by local app, key is
12
+ # a symbol for a semantic, value is a solr _stored_ field.
13
+ #
14
+ # Stored field can be single or multi-value. In some cases
15
+ # clients may only use the first value from a multi-value field.
16
+ #
17
+ # Currently documented semantic tokens, not all may be
18
+ # used by core BL, but some may be used by plugins present
19
+ # or future.
20
+ # :title, :author, :year, :language => User-presentable strings.
21
+ def field_semantics
22
+ @field_semantics ||= {}
23
+ end
24
+ end
25
+
26
+ # Returns a hash keyed by semantic tokens, value is an array of
27
+ # strings. (Array to handle multi-value fields). If no value(s)
28
+ # available, empty array is returned.
29
+ #
30
+ # Default implementation here uses field_semantics
31
+ # to just take values from Solr stored fields.
32
+ # Extensions can over-ride this method to provide better/different lookup,
33
+ # but extensions should call super and modify hash returned, to avoid
34
+ # unintentionally erasing values provided by other extensions.
35
+ def to_semantic_values
36
+ unless @semantic_value_hash
37
+ @semantic_value_hash = Hash.new([]) # default to empty array
38
+ self.class.field_semantics.each_pair do |key, field_name|
39
+ value = self[field_name]
40
+ # Make single and multi-values all arrays, so clients
41
+ # don't have to know.
42
+ unless value.nil?
43
+ value = [value] unless value.kind_of?(Array)
44
+ @semantic_value_hash[key] = value
45
+ end
46
+ end
47
+ end
48
+ return @semantic_value_hash
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # This module provides the body of an email export based on the document's semantic values
3
+ module Blacklight::Document::Sms
4
+
5
+ # Return a text string that will be the body of the email
6
+ def to_sms_text
7
+ semantics = self.to_semantic_values
8
+ body = []
9
+ body << I18n.t('blacklight.sms.text.title', value: semantics[:title].first) unless semantics[:title].blank?
10
+ body << I18n.t('blacklight.sms.text.author', value: semantics[:author].first) unless semantics[:author].blank?
11
+ return body.join unless body.empty?
12
+ end
13
+
14
+ end
@@ -55,7 +55,7 @@ module Blacklight
55
55
  # Render a value (or array of values) from a field
56
56
  #
57
57
  # @param [String] value or list of values to display
58
- # @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
58
+ # @param [Blacklight::Solr::Configuration::Field] solr field configuration
59
59
  # @return [String]
60
60
  def render_field_value value=nil, field_config=nil
61
61
  safe_values = Array(value).collect { |x| x.respond_to?(:force_encoding) ? x.force_encoding("UTF-8") : x }
@@ -134,7 +134,7 @@ module Blacklight
134
134
  # simplified by pushing some of this logic into the "model"
135
135
  # @param [SolrDocument] document
136
136
  # @param [String] field name
137
- # @param [Blacklight::Solr::Configuration::SolrField] solr field configuration
137
+ # @param [Blacklight::Solr::Configuration::Field] solr field configuration
138
138
  # @param [Hash] options additional options to pass to the rendering helpers
139
139
  def get_field_values field, field_config, options = {}
140
140
  # retrieving values
@@ -166,7 +166,7 @@ module Blacklight
166
166
  @controller.send(field_config.helper_method, options.merge(:document => @document, :field => field, :value => value))
167
167
  when (field_config and field_config.link_to_search)
168
168
  link_field = if field_config.link_to_search === true
169
- field_config.field
169
+ field_config.key
170
170
  else
171
171
  field_config.link_to_search
172
172
  end
@@ -6,10 +6,17 @@ module Blacklight
6
6
  end
7
7
 
8
8
  # When a request for a single solr document by id
9
- # is not successful, raise this:
9
+ # is not successful, we can raise this exception.
10
+ # Deprecated; this will be removed in Blacklight 6.0:
10
11
  class InvalidSolrID < RuntimeError
11
12
  end
12
-
13
+ # In Blacklight 6.0, this exception can subclass RuntimeError directly
14
+ class RecordNotFound < InvalidSolrID
15
+ end
16
+
17
+ class InvalidRequest < StandardError
18
+ end
19
+
13
20
  class ExpiredSessionToken < Exception
14
21
  end
15
22
 
@@ -8,11 +8,11 @@ module Blacklight
8
8
  Blacklight::Solr::FacetPaginator.new(display_facet.items,
9
9
  sort: display_facet.sort,
10
10
  offset: display_facet.offset,
11
- limit: facet_limit_for(field_config.field))
11
+ limit: facet_limit_for(field_config.key))
12
12
  end
13
13
 
14
14
  def facets_from_request(fields = facet_field_names)
15
- fields.map { |solr_field| facet_by_field_name(solr_field) }.compact
15
+ fields.map { |field| facet_by_field_name(field) }.compact
16
16
  end
17
17
 
18
18
  def facet_field_names
@@ -20,38 +20,43 @@ module Blacklight
20
20
  end
21
21
 
22
22
  def facet_configuration_for_field(field)
23
- blacklight_config.facet_fields[field] || Blacklight::Configuration::FacetField.new(:field => field).normalize!
23
+ f = blacklight_config.facet_fields[field]
24
+ f ||= begin
25
+ _, value = blacklight_config.facet_fields.find { |k,v| v.field == field }
26
+ value
27
+ end
28
+ f ||= Blacklight::Configuration::FacetField.new(:field => field).normalize!
24
29
  end
25
30
 
26
31
 
27
32
  # Get a FacetField object from the @response
28
- def facet_by_field_name solr_field
29
- case solr_field
33
+ def facet_by_field_name field
34
+ case field
30
35
  when String, Symbol
31
- extract_solr_facet_by_field_name(solr_field)
36
+ extract_facet_by_field_name(field)
32
37
  when Blacklight::Configuration::FacetField
33
- extract_solr_facet_by_field_name(solr_field.field)
38
+ extract_facet_by_field_name(field.key)
34
39
  else
35
- solr_field
40
+ field
36
41
  end
37
42
  end
38
43
 
39
44
  private
40
45
 
41
- # Get the solr response for the solr field :field
42
- def extract_solr_facet_by_field_name facet_name
43
- facet_field = facet_configuration_for_field(facet_name)
46
+ # Get the solr response for the field :field
47
+ def extract_facet_by_field_name field_name
48
+ facet_field = facet_configuration_for_field(field_name)
44
49
  case
45
50
  when (facet_field.respond_to?(:query) and facet_field.query)
46
- create_rsolr_facet_field_response_for_query_facet_field facet_name, facet_field
51
+ create_facet_field_response_for_query_facet_field field_name, facet_field
47
52
  when (facet_field.respond_to?(:pivot) and facet_field.pivot)
48
- create_rsolr_facet_field_response_for_pivot_facet_field facet_name, facet_field
53
+ create_facet_field_response_for_pivot_facet_field field_name, facet_field
49
54
  else
50
- @response.facet_by_field_name(facet_name)
55
+ @response.facet_by_field_name(field_name)
51
56
  end
52
57
  end
53
58
 
54
- def create_rsolr_facet_field_response_for_query_facet_field facet_name, facet_field
59
+ def create_facet_field_response_for_query_facet_field facet_name, facet_field
55
60
  salient_facet_queries = facet_field.query.map { |k, x| x[:fq] }
56
61
  items = []
57
62
  @response.facet_queries.select { |k,v| salient_facet_queries.include?(k) }.reject { |value, hits| hits == 0 }.map do |value,hits|
@@ -64,7 +69,7 @@ module Blacklight
64
69
  end
65
70
 
66
71
 
67
- def create_rsolr_facet_field_response_for_pivot_facet_field facet_name, facet_field
72
+ def create_facet_field_response_for_pivot_facet_field facet_name, facet_field
68
73
  items = []
69
74
  (@response.facet_pivot[facet_field.pivot.join(",")] || []).map do |lst|
70
75
  items << construct_pivot_field(lst)
@@ -1,6 +1,6 @@
1
1
  module Blacklight
2
2
  ##
3
- # This module contains methods that are specified by SolrHelper.solr_search_params_logic
3
+ # This module contains methods that are specified by SearchHelper.search_params_logic
4
4
  # They transform user parameters into parameters that are sent as a request to Solr when
5
5
  # RequestBuilders#solr_search_params is called.
6
6
  #
@@ -10,26 +10,56 @@ module Blacklight
10
10
  self.deprecation_horizon = 'blacklight 6.0'
11
11
 
12
12
  included do
13
- # We want to install a class-level place to keep
14
- # solr_search_params_logic method names. Compare to before_filter,
13
+ # We want to install a class-level place to keep
14
+ # search_params_logic method names. Compare to before_filter,
15
15
  # similar design. Since we're a module, we have to add it in here.
16
16
  # There are too many different semantic choices in ruby 'class variables',
17
- # we choose this one for now, supplied by Rails.
18
- class_attribute :solr_search_params_logic
17
+ # we choose this one for now, supplied by Rails.
18
+ class_attribute :search_params_logic
19
+
20
+ alias_method :solr_search_params_logic, :search_params_logic
21
+ deprecation_deprecate solr_search_params_logic: :search_params_logic
22
+
23
+ alias_method :solr_search_params_logic=, :search_params_logic=
24
+ deprecation_deprecate :solr_search_params_logic= => :search_params_logic=
19
25
 
20
26
  # Set defaults. Each symbol identifies a _method_ that must be in
21
27
  # this class, taking two parameters (solr_parameters, user_parameters)
22
28
  # Can be changed in local apps or by plugins, eg:
23
29
  # CatalogController.include ModuleDefiningNewMethod
24
- # CatalogController.solr_search_params_logic += [:new_method]
25
- # CatalogController.solr_search_params_logic.delete(:we_dont_want)
26
- self.solr_search_params_logic = [:default_solr_parameters, :add_query_to_solr, :add_facet_fq_to_solr, :add_facetting_to_solr, :add_solr_fields_to_query, :add_paging_to_solr, :add_sorting_to_solr, :add_group_config_to_solr ]
30
+ # CatalogController.search_params_logic += [:new_method]
31
+ # CatalogController.search_params_logic.delete(:we_dont_want)
32
+ self.search_params_logic = [:default_solr_parameters, :add_query_to_solr, :add_facet_fq_to_solr, :add_facetting_to_solr, :add_solr_fields_to_query, :add_paging_to_solr, :add_sorting_to_solr, :add_group_config_to_solr ]
27
33
 
28
34
  if self.respond_to?(:helper_method)
29
35
  helper_method(:facet_limit_for)
30
36
  end
31
37
  end
32
38
 
39
+ module ClassMethods
40
+ extend Deprecation
41
+ self.deprecation_horizon = 'blacklight 6.0'
42
+
43
+ def solr_search_params_logic
44
+ search_params_logic
45
+ end
46
+ deprecation_deprecate solr_search_params_logic: :search_params_logic
47
+
48
+ def solr_search_params_logic= logic
49
+ self.search_params_logic= logic
50
+ end
51
+ deprecation_deprecate :solr_search_params_logic= => :search_params_logic=
52
+ end
53
+
54
+ def search_builder_class
55
+ blacklight_config.search_builder_class
56
+ end
57
+
58
+ def search_builder processor_chain = search_params_logic
59
+ search_builder_class.new(processor_chain, self)
60
+ end
61
+
62
+
33
63
  # @returns a params hash for searching solr.
34
64
  # The CatalogController #index action uses this.
35
65
  # Solr parameters can come from a number of places. From lowest
@@ -45,32 +75,37 @@ module Blacklight
45
75
  # specified otherwise.
46
76
  #
47
77
  # Incoming parameter :f is mapped to :fq solr parameter.
48
- def solr_search_params(user_params = params || {})
49
- Blacklight::Solr::Request.new.tap do |solr_parameters|
50
- solr_search_params_logic.each do |method_name|
51
- send(method_name, solr_parameters, user_params)
52
- end
53
- end
78
+ def solr_search_params(user_params = params || {}, processor_chain = search_params_logic)
79
+ search_builder(processor_chain).with(user_params).processed_parameters
54
80
  end
55
-
81
+ deprecation_deprecate solr_search_params: :processed_parameters
82
+
83
+ ##
84
+ # @param [Hash] user_params a hash of user submitted parameters
85
+ # @param [Array] processor_chain a list of processor methods to run
86
+ # @param [Hash] extra_params an optional hash of parameters that should be
87
+ # added to the query post processing
88
+ def build_solr_query(user_params, processor_chain, extra_params=nil)
89
+ search_builder(processor_chain).with(user_params).query(extra_params)
90
+ end
91
+ deprecation_deprecate build_solr_query: :query
92
+
56
93
  ##
57
94
  # Retrieve the results for a list of document ids
58
95
  def solr_document_ids_params(ids = [])
59
- solr_documents_by_field_values_params blacklight_config.solr_document_model.unique_key, ids
96
+ Deprecation.silence(Blacklight::RequestBuilders) do
97
+ solr_documents_by_field_values_params blacklight_config.document_model.unique_key, ids
98
+ end
60
99
  end
100
+ deprecation_deprecate :solr_document_ids_params
61
101
 
62
102
  ##
63
103
  # Retrieve the results for a list of document ids
64
104
  # @deprecated
65
105
  def solr_documents_by_field_values_params(field, values)
66
- q = if Array(values).empty?
67
- "{!lucene}NOT *:*"
68
- else
69
- "{!lucene}#{field}:(#{ Array(values).map { |x| solr_param_quote(x) }.join(" OR ")})"
70
- end
71
-
72
- { q: q, spellcheck: 'false', fl: "*" }
106
+ search_builder([:add_query_to_solr]).with(q: { field => values}).query(fl: '*')
73
107
  end
108
+ deprecation_deprecate :solr_documents_by_field_values_params
74
109
 
75
110
  ##
76
111
  # Retrieve a facet's paginated values.
@@ -81,7 +116,7 @@ module Blacklight
81
116
  solr_params = {}
82
117
 
83
118
  # Now override with our specific things for fetching facet values
84
- solr_params[:"facet.field"] = with_ex_local_param((facet_config.ex if facet_config.respond_to?(:ex)), facet_field)
119
+ solr_params[:"facet.field"] = search_builder.with_ex_local_param((facet_config.ex if facet_config.respond_to?(:ex)), facet_field)
85
120
 
86
121
  limit = if respond_to?(:facet_list_limit)
87
122
  facet_list_limit.to_s.to_i
@@ -132,219 +167,12 @@ module Blacklight
132
167
  solr_params[:facet] = false
133
168
  solr_params
134
169
  end
135
-
136
- ####
137
- # Start with general defaults from BL config. Need to use custom
138
- # merge to dup values, to avoid later mutating the original by mistake.
139
- def default_solr_parameters(solr_parameters, user_params)
140
- blacklight_config.default_solr_params.each do |key, value|
141
- solr_parameters[key] = value.dup rescue value
142
- end
143
- end
144
-
145
- ##
146
- # Take the user-entered query, and put it in the solr params,
147
- # including config's "search field" params for current search field.
148
- # also include setting spellcheck.q.
149
- def add_query_to_solr(solr_parameters, user_parameters)
150
- ###
151
- # Merge in search field configured values, if present, over-writing general
152
- # defaults
153
- ###
154
- # legacy behavior of user param :qt is passed through, but over-ridden
155
- # by actual search field config if present. We might want to remove
156
- # this legacy behavior at some point. It does not seem to be currently
157
- # rspec'd.
158
- solr_parameters[:qt] = user_parameters[:qt] if user_parameters[:qt]
159
-
160
- search_field_def = blacklight_config.search_fields[user_parameters[:search_field]]
161
- if (search_field_def)
162
- solr_parameters[:qt] = search_field_def.qt
163
- solr_parameters.merge!( search_field_def.solr_parameters) if search_field_def.solr_parameters
164
- end
165
-
166
- ##
167
- # Create Solr 'q' including the user-entered q, prefixed by any
168
- # solr LocalParams in config, using solr LocalParams syntax.
169
- # http://wiki.apache.org/solr/LocalParams
170
- ##
171
- if (search_field_def && hash = search_field_def.solr_local_parameters)
172
- local_params = hash.collect do |key, val|
173
- key.to_s + "=" + solr_param_quote(val, :quote => "'")
174
- end.join(" ")
175
- solr_parameters[:q] = "{!#{local_params}}#{user_parameters[:q]}"
176
- else
177
- solr_parameters[:q] = user_parameters[:q] if user_parameters[:q]
178
- end
179
-
180
-
181
- ##
182
- # Set Solr spellcheck.q to be original user-entered query, without
183
- # our local params, otherwise it'll try and spellcheck the local
184
- # params! Unless spellcheck.q has already been set by someone,
185
- # respect that.
186
- #
187
- # TODO: Change calling code to expect this as a symbol instead of
188
- # a string, for consistency? :'spellcheck.q' is a symbol. Right now
189
- # rspec tests for a string, and can't tell if other code may
190
- # insist on a string.
191
- solr_parameters["spellcheck.q"] = user_parameters[:q] unless solr_parameters["spellcheck.q"]
192
- end
193
-
194
- ##
195
- # Add any existing facet limits, stored in app-level HTTP query
196
- # as :f, to solr as appropriate :fq query.
197
- def add_facet_fq_to_solr(solr_parameters, user_params)
198
-
199
- # convert a String value into an Array
200
- if solr_parameters[:fq].is_a? String
201
- solr_parameters[:fq] = [solr_parameters[:fq]]
202
- end
203
-
204
- # :fq, map from :f.
205
- if ( user_params[:f])
206
- f_request_params = user_params[:f]
207
-
208
- f_request_params.each_pair do |facet_field, value_list|
209
- Array(value_list).each do |value|
210
- next if value.blank? # skip empty strings
211
- solr_parameters.append_filter_query facet_value_to_fq_string(facet_field, value)
212
- end
213
- end
214
- end
215
- end
216
170
 
217
- ##
218
- # Add appropriate Solr facetting directives in, including
219
- # taking account of our facet paging/'more'. This is not
220
- # about solr 'fq', this is about solr facet.* params.
221
- def add_facetting_to_solr(solr_parameters, user_params)
222
- # While not used by BL core behavior, legacy behavior seemed to be
223
- # to accept incoming params as "facet.field" or "facets", and add them
224
- # on to any existing facet.field sent to Solr. Legacy behavior seemed
225
- # to be accepting these incoming params as arrays (in Rails URL with []
226
- # on end), or single values. At least one of these is used by
227
- # Stanford for "faux hieararchial facets".
228
- if user_params.has_key?("facet.field") || user_params.has_key?("facets")
229
- solr_parameters[:"facet.field"].concat( [user_params["facet.field"], user_params["facets"]].flatten.compact ).uniq!
230
- end
231
-
232
- blacklight_config.facet_fields.select { |field_name,facet|
233
- facet.include_in_request || (facet.include_in_request.nil? && blacklight_config.add_facet_fields_to_solr_request)
234
- }.each do |field_name, facet|
235
- solr_parameters[:facet] ||= true
236
-
237
- case
238
- when facet.pivot
239
- solr_parameters.append_facet_pivot with_ex_local_param(facet.ex, facet.pivot.join(","))
240
- when facet.query
241
- solr_parameters.append_facet_query facet.query.map { |k, x| with_ex_local_param(facet.ex, x[:fq]) }
242
- else
243
- solr_parameters.append_facet_fields with_ex_local_param(facet.ex, facet.field)
244
- end
245
-
246
- if facet.sort
247
- solr_parameters[:"f.#{facet.field}.facet.sort"] = facet.sort
248
- end
249
-
250
- if facet.solr_params
251
- facet.solr_params.each do |k, v|
252
- solr_parameters[:"f.#{facet.field}.#{k}"] = v
253
- end
254
- end
255
-
256
- # Support facet paging and 'more'
257
- # links, by sending a facet.limit one more than what we
258
- # want to page at, according to configured facet limits.
259
- solr_parameters[:"f.#{facet.field}.facet.limit"] = (facet_limit_for(field_name) + 1) if facet_limit_for(field_name)
260
- end
261
- end
262
-
263
- def add_solr_fields_to_query solr_parameters, user_parameters
264
- blacklight_config.show_fields.select(&method(:should_add_to_solr)).each do |field_name, field|
265
- if field.solr_params
266
- field.solr_params.each do |k, v|
267
- solr_parameters[:"f.#{field.field}.#{k}"] = v
268
- end
269
- end
270
- end
271
-
272
- blacklight_config.index_fields.select(&method(:should_add_to_solr)).each do |field_name, field|
273
- if field.highlight
274
- solr_parameters[:hl] = true
275
- solr_parameters.append_highlight_field field.field
276
- end
277
-
278
- if field.solr_params
279
- field.solr_params.each do |k, v|
280
- solr_parameters[:"f.#{field.field}.#{k}"] = v
281
- end
282
- end
283
- end
284
- end
285
-
286
- ###
287
- # copy paging params from BL app over to solr, changing
288
- # app level per_page and page to Solr rows and start.
289
- def add_paging_to_solr(solr_params, user_params)
290
-
291
- # user-provided parameters should override any default row
292
- solr_params[:rows] = user_params[:rows].to_i unless user_params[:rows].blank?
293
- solr_params[:rows] = user_params[:per_page].to_i unless user_params[:per_page].blank?
294
-
295
- # configuration defaults should only set a default value, not override a value set elsewhere (e.g. search field parameters)
296
- solr_params[:rows] ||= blacklight_config.default_per_page unless blacklight_config.default_per_page.blank?
297
- solr_params[:rows] ||= blacklight_config.per_page.first unless blacklight_config.per_page.blank?
298
-
299
- # set a reasonable default
300
- Rails.logger.info "Solr :rows parameter not set (by the user, configuration, or default solr parameters); using 10 rows by default"
301
- solr_params[:rows] ||= 10
302
-
303
- # ensure we don't excede the max page size
304
- solr_params[:rows] = blacklight_config.max_per_page if solr_params[:rows].to_i > blacklight_config.max_per_page
305
- unless user_params[:page].blank?
306
- solr_params[:start] = solr_params[:rows].to_i * (user_params[:page].to_i - 1)
307
- solr_params[:start] = 0 if solr_params[:start].to_i < 0
308
- end
309
-
310
- end
311
-
312
- ###
313
- # copy sorting params from BL app over to solr
314
- def add_sorting_to_solr(solr_parameters, user_params)
315
- if user_params[:sort].blank? and sort_field = blacklight_config.default_sort_field
316
- # no sort param provided, use default
317
- solr_parameters[:sort] = sort_field.sort unless sort_field.sort.blank?
318
- elsif sort_field = blacklight_config.sort_fields[user_params[:sort]]
319
- # check for sort field key
320
- solr_parameters[:sort] = sort_field.sort unless sort_field.sort.blank?
321
- else
322
- # just pass the key through
323
- solr_parameters[:sort] = user_params[:sort]
324
- end
325
- end
326
-
327
- # Remove the group parameter if we've faceted on the group field (e.g. for the full results for a group)
328
- def add_group_config_to_solr solr_parameters, user_parameters
329
- if user_parameters[:f] and user_parameters[:f][grouped_key_for_results]
330
- solr_parameters[:group] = false
331
- end
332
- end
333
-
334
- def with_ex_local_param(ex, value)
335
- if ex
336
- "{!ex=#{ex}}#{value}"
337
- else
338
- value
339
- end
340
- end
341
-
342
-
343
171
  DEFAULT_FACET_LIMIT = 10
344
172
 
345
173
  # Look up facet limit for given facet_field. Will look at config, and
346
174
  # if config is 'true' will look up from Solr @response if available. If
347
- # no limit is avaialble, returns nil. Used from #solr_search_params
175
+ # no limit is avaialble, returns nil. Used from #add_facetting_to_solr
348
176
  # to supply f.fieldname.facet.limit values in solr request (no @response
349
177
  # available), and used in display (with @response available) to create
350
178
  # a facet paginator with the right limit.
@@ -366,57 +194,5 @@ module Blacklight
366
194
  facet.limit == true ? DEFAULT_FACET_LIMIT : facet.limit
367
195
  end
368
196
  end
369
-
370
- ##
371
- # A helper method used for generating solr LocalParams, put quotes
372
- # around the term unless it's a bare-word. Escape internal quotes
373
- # if needed.
374
- def solr_param_quote(val, options = {})
375
- options[:quote] ||= '"'
376
- unless val =~ /^[a-zA-Z0-9$_\-\^]+$/
377
- val = options[:quote] +
378
- # Yes, we need crazy escaping here, to deal with regexp esc too!
379
- val.gsub("'", "\\\\\'").gsub('"', "\\\\\"") +
380
- options[:quote]
381
- end
382
- return val
383
- end
384
-
385
- private
386
-
387
- def should_add_to_solr field_name, field
388
- field.include_in_request || (field.include_in_request.nil? && blacklight_config.add_field_configuration_to_solr_request)
389
- end
390
-
391
- ##
392
- # Convert a facet/value pair into a solr fq parameter
393
- def facet_value_to_fq_string(facet_field, value)
394
- facet_config = blacklight_config.facet_fields[facet_field]
395
-
396
- local_params = []
397
- local_params << "tag=#{facet_config.tag}" if facet_config and facet_config.tag
398
-
399
- prefix = ""
400
- prefix = "{!#{local_params.join(" ")}}" unless local_params.empty?
401
-
402
- fq = case
403
- when (facet_config and facet_config.query)
404
- facet_config.query[value][:fq]
405
- when (facet_config and facet_config.date)
406
- # in solr 3.2+, this could be replaced by a !term query
407
- "#{prefix}#{facet_field}:#{RSolr.escape(value)}"
408
- when (value.is_a?(DateTime) or value.is_a?(Date) or value.is_a?(Time))
409
- "#{prefix}#{facet_field}:#{RSolr.escape(value.to_time.utc.strftime("%Y-%m-%dT%H:%M:%SZ"))}"
410
- when (value.is_a?(TrueClass) or value.is_a?(FalseClass) or value == 'true' or value == 'false'),
411
- (value.is_a?(Integer) or (value.to_i.to_s == value if value.respond_to? :to_i)),
412
- (value.is_a?(Float) or (value.to_f.to_s == value if value.respond_to? :to_f))
413
- "#{prefix}#{facet_field}:#{RSolr.escape(value.to_s)}"
414
- when value.is_a?(Range)
415
- "#{prefix}#{facet_field}:[#{value.first} TO #{value.last}]"
416
- else
417
- "{!raw f=#{facet_field}#{(" " + local_params.join(" ")) unless local_params.empty?}}#{value}"
418
- end
419
-
420
- end
421
197
  end
422
198
  end