blacklight 5.9.3 → 5.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -3
  3. data/Rakefile +1 -2
  4. data/VERSION +1 -1
  5. data/app/helpers/blacklight/blacklight_helper_behavior.rb +4 -2
  6. data/app/helpers/blacklight/configuration_helper_behavior.rb +5 -7
  7. data/app/models/bookmark.rb +4 -1
  8. data/app/models/search.rb +6 -3
  9. data/app/views/catalog/_home_text.html.erb +48 -8
  10. data/app/views/catalog/_sms_form.html.erb +1 -1
  11. data/blacklight.gemspec +1 -1
  12. data/config/jetty.yml +3 -0
  13. data/doc/Adding-new-document-actions.md +94 -0
  14. data/doc/Atom-Responses.md +90 -0
  15. data/doc/Blacklight-Add-ons.md +23 -0
  16. data/doc/Blacklight-configuration.md +411 -0
  17. data/doc/Blacklight-on-Heroku.md +100 -0
  18. data/doc/Blacklight-out-of-the-box.md +47 -0
  19. data/doc/Bookmarks.md +1 -0
  20. data/doc/Code4Lib-2014.md +94 -0
  21. data/doc/Configuration---Facet-Fields.md +130 -0
  22. data/doc/Configuration---Results-View.md +224 -0
  23. data/doc/Configuration---Solr-fields.md +106 -0
  24. data/doc/Configuring-and-Customizing-Blacklight.md +257 -0
  25. data/doc/Configuring-rails-routes.md +13 -0
  26. data/doc/Contributing-to-Blacklight.md +43 -0
  27. data/doc/Examples.md +120 -0
  28. data/doc/Extending-or-Modifying-Blacklight-Search-Behavior.md +141 -0
  29. data/doc/Home.md +100 -0
  30. data/doc/How-to-release-a-version.md +45 -0
  31. data/doc/Indexing-your-data-into-solr.md +36 -0
  32. data/doc/Internationalization.md +32 -0
  33. data/doc/JSON-API.md +83 -0
  34. data/doc/Pagination.md +52 -0
  35. data/doc/Providing-your-own-view-templates.md +69 -0
  36. data/doc/Quickstart.md +153 -0
  37. data/doc/README_SOLR.md +245 -0
  38. data/doc/Saved-Searches.md +5 -0
  39. data/doc/Solr-Configuration.md +154 -0
  40. data/doc/Sunspot-for-indexing.md +46 -0
  41. data/doc/Support.md +33 -0
  42. data/doc/Theming.md +62 -0
  43. data/doc/Understanding-Rails-and-Blacklight.md +75 -0
  44. data/doc/User-Authentication.md +60 -0
  45. data/doc/_Sidebar.md +9 -0
  46. data/doc/testing.md +58 -0
  47. data/lib/blacklight.rb +11 -3
  48. data/lib/blacklight/catalog.rb +16 -5
  49. data/lib/blacklight/catalog/search_context.rb +2 -0
  50. data/lib/blacklight/configuration/facet_field.rb +1 -1
  51. data/lib/blacklight/configuration/search_field.rb +1 -1
  52. data/lib/blacklight/routes.rb +3 -1
  53. data/lib/blacklight/solr/document.rb +24 -8
  54. data/lib/blacklight/solr_repository.rb +2 -2
  55. data/lib/blacklight/utils.rb +23 -0
  56. data/lib/generators/blacklight/install_generator.rb +1 -1
  57. data/lib/generators/blacklight/models_generator.rb +3 -1
  58. data/lib/generators/blacklight/templates/config/jetty.yml +3 -0
  59. data/spec/controllers/catalog_controller_spec.rb +9 -20
  60. data/spec/helpers/blacklight_helper_spec.rb +44 -0
  61. data/spec/helpers/configuration_helper_spec.rb +7 -0
  62. data/spec/lib/blacklight/configuration_spec.rb +33 -6
  63. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  64. data/tasks/blacklight.rake +6 -4
  65. metadata +38 -4
data/doc/testing.md ADDED
@@ -0,0 +1,58 @@
1
+ ## Using Blacklight source checkout as gem for development
2
+
3
+ The ordinary install instructions install the BL gem (which is not
4
+ full source code) in wherever your system installs gems.
5
+
6
+ Sometimes, especially for development, it's useful to check out
7
+ a complete copy of the blacklight source code, and link your app
8
+ to that as a 'gem' instead.
9
+
10
+ Checkout the code:
11
+
12
+ $ git clone git@github.com:projectblacklight/blacklight.git
13
+
14
+
15
+ ## Automatically generate a test application (and run the tests)
16
+
17
+ To run the Blacklight test suite, Blacklight comes with a rake task that creates local dependencies like a Solr with indexed test data and a test Rails application, and then runs tests.
18
+
19
+ Requirements:
20
+
21
+ * Java (1.6 or above) (for Solr)
22
+ * phantomjs (used by integration tests, you may be able to install with your local package manager, for instance on OSX with `brew install phantomjs`)
23
+
24
+ Then from the root directory of your blacklight git checkout:
25
+
26
+ ```
27
+ bundle exec rake
28
+ ```
29
+
30
+ This ensure a test Solr exists and is running, creates a test application, and loads the fixtures and then runs specs and cucumber tests.
31
+
32
+ ### Step by step, with more control
33
+
34
+ `rake ci` will, every time you run it, re-index test data in solr, and re-build the test application. Re-building the test application in particular is kind of time-consuming. You may prefer to set up the environment and run tests as separate steps, to make development easier.
35
+
36
+ To create the dummy test app:
37
+
38
+ $ bundle exec rake engine_cart:generate
39
+
40
+ (If you have an existing dummy app that is outdated, `rake engine_cart:clean` first, then `rake engine_cart:generate).
41
+
42
+ Then start up the test jetty, on the port that tests will look for it, with:
43
+
44
+ $ RAILS_ENV=test bundle exec rake jetty:start
45
+
46
+ If you haven't yet indexed the test data in the test jetty. (??? Not sure how to do this. Run `rake ci` once to make sure test data has been indexed). Run `rake jetty:stop` when you're done with it.
47
+
48
+ Then run all the specs with:
49
+
50
+ $ bundle exec rake spec
51
+
52
+ Or just run one spec
53
+
54
+ $ bundle exec rake spec SPEC=just/one_spec.rb
55
+
56
+ And stop your test solr when you're done with it:
57
+
58
+ $ bundle exec rake jetty:stop
data/lib/blacklight.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require 'kaminari'
3
3
  require 'rsolr'
4
+ require 'deprecation'
5
+ require 'blacklight/utils'
6
+
4
7
  module Blacklight
5
8
 
6
9
  autoload :Configurable, 'blacklight/configurable'
@@ -25,8 +28,7 @@ module Blacklight
25
28
  autoload :DocumentPresenter, 'blacklight/document_presenter'
26
29
 
27
30
  autoload :Routes, 'blacklight/routes'
28
-
29
- autoload :OpenStructWithHashAccess, 'blacklight/utils'
31
+
30
32
  autoload :SolrResponse, 'blacklight/solr_response'
31
33
  autoload :Facet, 'blacklight/facet'
32
34
 
@@ -92,7 +94,13 @@ module Blacklight
92
94
  end
93
95
 
94
96
  def self.logger
95
- ::Rails.logger
97
+ @logger ||= begin
98
+ ::Rails.logger if defined? Rails and Rails.respond_to? :logger
99
+ end
100
+ end
101
+
102
+ def self.logger= logger
103
+ @logger = logger
96
104
  end
97
105
 
98
106
  #############
@@ -33,7 +33,7 @@ module Blacklight::Catalog
33
33
  (@response, @document_list) = get_search_results
34
34
 
35
35
  respond_to do |format|
36
- format.html { preferred_view }
36
+ format.html { store_preferred_view }
37
37
  format.rss { render :layout => false }
38
38
  format.atom { render :layout => false }
39
39
  format.json do
@@ -45,7 +45,8 @@ module Blacklight::Catalog
45
45
  end
46
46
  end
47
47
 
48
- # get single document from the solr index
48
+ # get a single document from the index
49
+ # to add responses for formats other than html or json see _Blacklight::Document::Export_
49
50
  def show
50
51
  @response, @document = get_solr_response_for_doc_id params[:id]
51
52
 
@@ -134,13 +135,23 @@ module Blacklight::Catalog
134
135
  # do not specifiy the view, set the view parameter to the value stored in the
135
136
  # session. This enables a user with a session to do subsequent searches and have
136
137
  # them default to the last used view.
137
- def preferred_view
138
+ def store_preferred_view
138
139
  session[:preferred_view] = params[:view] if params[:view]
139
- params[:view] ||= session[:preferred_view]
140
140
  end
141
141
 
142
+ alias_method :preferred_view, :store_preferred_view
143
+ deprecation_deprecate :preferred_view
144
+
142
145
  ##
143
- # Render additional response formats, as provided by the blacklight configuration
146
+ # Render additional response formats for the index action, as provided by the
147
+ # blacklight configuration
148
+ #
149
+ # example:
150
+ #
151
+ # config.index.respond_to.txt = Proc.new { render text: "A list of docs." }
152
+ #
153
+ # Make sure your format has a well known mime-type or is registered in
154
+ # config/initializers/mime_types.rb
144
155
  def additional_response_formats format
145
156
  blacklight_config.index.respond_to.each do |key, config|
146
157
  format.send key do
@@ -101,6 +101,8 @@ module Blacklight::Catalog::SearchContext
101
101
  @previous_document = documents.first
102
102
  @next_document = documents.last
103
103
  end
104
+ rescue Blacklight::Exceptions::InvalidRequest => e
105
+ logger.warn "Unable to setup next and previous documents: #{e}"
104
106
  end
105
107
 
106
108
  end
@@ -10,7 +10,7 @@ module Blacklight
10
10
 
11
11
  self.collapse = true if self.collapse.nil?
12
12
  self.show = true if self.show.nil?
13
- self.if ||= self.show
13
+ self.if = self.show if self.if.nil?
14
14
 
15
15
  super
16
16
  end
@@ -7,7 +7,7 @@ module Blacklight
7
7
  self.field ||= self.key
8
8
  self.label ||= self.key.try(:titlecase)
9
9
  self.qt ||= blacklight_config.default_solr_params[:qt] if blacklight_config && blacklight_config.default_solr_params
10
- self.if ||= self.include_in_simple_select
10
+ self.if = self.include_in_simple_select if self.if.nil?
11
11
  super
12
12
  end
13
13
 
@@ -19,7 +19,9 @@ module Blacklight
19
19
  # klass.default_route_sets += [:widget_routing]
20
20
  # end
21
21
  # def widget_routing(primary_resource)
22
- # get "#{primary_resource}/widget", "#{primary_resource}#widget"
22
+ # add_routes do |options|
23
+ # get "#{primary_resource}/widget", "#{primary_resource}#widget"
24
+ # end
23
25
  # end
24
26
  # end
25
27
  # Blacklight::Routes.send(:include, MyWidget::Routes)
@@ -34,7 +34,7 @@ module Blacklight::Solr::Document
34
34
  include Blacklight::Solr::Document::Extensions
35
35
  end
36
36
 
37
- attr_reader :solr_response
37
+ attr_reader :solr_response, :_source
38
38
 
39
39
  def initialize(source_doc={}, solr_response=nil)
40
40
  @_source = source_doc.with_indifferent_access
@@ -54,11 +54,23 @@ module Blacklight::Solr::Document
54
54
  # If a method is missing, it gets sent to @_source
55
55
  # with all of the original params and block
56
56
  def method_missing(m, *args, &b)
57
- @_source.send(m, *args, &b)
57
+ if _source_responds_to?(m)
58
+ _source.send(m, *args, &b)
59
+ else
60
+ super
61
+ end
62
+ end
63
+
64
+ def respond_to_missing? *args
65
+ _source_responds_to?(*args) || super
58
66
  end
59
67
 
60
68
  def [] *args
61
- @_source.send :[], *args
69
+ _source.send :[], *args
70
+ end
71
+
72
+ def _read_attribute(attr)
73
+ self[attr]
62
74
  end
63
75
 
64
76
  # Helper method to check if value/multi-values exist for a given key.
@@ -83,8 +95,9 @@ module Blacklight::Solr::Document
83
95
  end
84
96
 
85
97
  def key? k
86
- @_source.key? k
98
+ _source.key? k
87
99
  end
100
+ alias_method :has_key?, :key?
88
101
 
89
102
  def has_highlight_field? k
90
103
  return false if @solr_response['highlighting'].blank? or @solr_response['highlighting'][self.id].blank?
@@ -126,7 +139,7 @@ module Blacklight::Solr::Document
126
139
  end
127
140
 
128
141
  def as_json(options = nil)
129
- @_source.as_json(options)
142
+ _source.as_json(options)
130
143
  end
131
144
 
132
145
  def to_partial_path
@@ -203,7 +216,10 @@ module Blacklight::Solr::Document
203
216
  @field_semantics ||= {}
204
217
  end
205
218
  end
206
-
207
-
208
-
219
+ private
220
+
221
+ def _source_responds_to? *args
222
+ _source && self != _source && _source.respond_to?(*args)
223
+ end
224
+
209
225
  end
@@ -49,8 +49,8 @@ module Blacklight
49
49
 
50
50
  solr_response = blacklight_config.solr_response_model.new(res, solr_params, solr_document_model: blacklight_config.solr_document_model)
51
51
 
52
- Rails.logger.debug("Solr query: #{solr_params.inspect}")
53
- Rails.logger.debug("Solr response: #{solr_response.inspect}") if defined?(::BLACKLIGHT_VERBOSE_LOGGING) and ::BLACKLIGHT_VERBOSE_LOGGING
52
+ Blacklight.logger.debug("Solr query: #{solr_params.inspect}")
53
+ Blacklight.logger.debug("Solr response: #{solr_response.inspect}") if defined?(::BLACKLIGHT_VERBOSE_LOGGING) and ::BLACKLIGHT_VERBOSE_LOGGING
54
54
  solr_response
55
55
  end
56
56
  rescue Errno::ECONNREFUSED => e
@@ -1,5 +1,28 @@
1
1
  require 'ostruct'
2
2
  module Blacklight
3
+
4
+ module Utils
5
+ def self.needs_attr_accessible?
6
+ if rails_3?
7
+ !strong_parameters_enabled?
8
+ else
9
+ protected_attributes_enabled?
10
+ end
11
+ end
12
+
13
+ def self.rails_3?
14
+ Rails::VERSION::MAJOR == 3
15
+ end
16
+
17
+ def self.strong_parameters_enabled?
18
+ defined?(ActionController::StrongParameters)
19
+ end
20
+
21
+ def self.protected_attributes_enabled?
22
+ defined?(ActiveModel::MassAssignmentSecurity)
23
+ end
24
+ end
25
+
3
26
  ##
4
27
  # An OpenStruct that responds to common Hash methods
5
28
  class OpenStructWithHashAccess < OpenStruct
@@ -72,7 +72,7 @@ module Blacklight
72
72
 
73
73
  def generate_blacklight_marc_demo
74
74
  if options[:marc]
75
- gem "blacklight-marc", "~> 5.0"
75
+ gem "blacklight-marc", "5.5.0"
76
76
 
77
77
  Bundler.with_clean_env do
78
78
  run "bundle install"
@@ -69,7 +69,9 @@ This generator makes the following changes to your application:
69
69
  file_path = "app/models/#{model_name.underscore}.rb"
70
70
  if File.exists?(file_path)
71
71
  inject_into_class file_path, model_name.classify do
72
- "\n attr_accessible :email, :password, :password_confirmation if Rails::VERSION::MAJOR < 4\n" +
72
+ "\n if Blacklight::Utils.needs_attr_accessible?\n" +
73
+ "\n attr_accessible :email, :password, :password_confirmation" +
74
+ "\n end\n" +
73
75
  "# Connects this user object to Blacklights Bookmarks. " +
74
76
  "\n include Blacklight::User\n"
75
77
  end
@@ -1,10 +1,13 @@
1
1
  development:
2
2
  startup_wait: 15
3
3
  jetty_port: 8983
4
+ java_version: ">= 1.7"
4
5
  test:
5
6
  startup_wait: 60
6
7
  jetty_port: <%= ENV['TEST_JETTY_PORT'] || 8888 %>
7
8
  <%= ENV['TEST_JETTY_PATH'] ? "jetty_home: " + ENV['TEST_JETTY_PATH'] : '' %>
9
+ java_version: ">= 1.7"
8
10
  production:
9
11
  startup_wait: 15
10
12
  jetty_port: 8983
13
+ java_version: ">= 1.7"
@@ -33,26 +33,6 @@ describe CatalogController do
33
33
  get :index, q: 'foo', view: 'gallery'
34
34
  expect(session[:preferred_view]).to eq 'gallery'
35
35
  end
36
-
37
- context "when they have a preferred view" do
38
- before do
39
- session[:preferred_view] = 'gallery'
40
- end
41
-
42
- context "and no view is specified" do
43
- it "should use the saved preference" do
44
- get :index, q: 'foo'
45
- expect(controller.params[:view]).to eq 'gallery'
46
- end
47
- end
48
-
49
- context "and a view is specified" do
50
- it "should use the saved preference" do
51
- get :index, q: 'foo', view: 'list'
52
- expect(controller.params[:view]).to eq 'list'
53
- end
54
- end
55
- end
56
36
  end
57
37
 
58
38
  # check each user manipulated parameter
@@ -313,6 +293,15 @@ describe CatalogController do
313
293
  get :show, :id => doc_id
314
294
  expect(assigns[:next_document]).to_not be_nil
315
295
  end
296
+
297
+ it "should not break if solr returns an exception" do
298
+ allow(controller).to receive(:get_previous_and_next_documents_for_search) {
299
+ raise Blacklight::Exceptions::InvalidRequest.new "Error"
300
+ }
301
+ get :show, :id => doc_id
302
+ expect(assigns[:previous_document]).to be_nil
303
+ expect(assigns[:next_document]).to be_nil
304
+ end
316
305
  end
317
306
 
318
307
  # NOTE: status code is always 200 in isolation mode ...
@@ -612,6 +612,50 @@ describe BlacklightHelper do
612
612
  end
613
613
  end
614
614
 
615
+ describe "#document_index_view_type" do
616
+ it "should default to the default view" do
617
+ allow(helper).to receive(:document_index_views).and_return(a: 1, b: 2)
618
+ allow(helper).to receive(:default_document_index_view_type).and_return(:xyz)
619
+ expect(helper.document_index_view_type).to eq :xyz
620
+ end
621
+
622
+ it "should use the query parameter" do
623
+ allow(helper).to receive(:document_index_views).and_return(a: 1, b: 2)
624
+ expect(helper.document_index_view_type(view: :a)).to eq :a
625
+ end
626
+
627
+ it "should use the default view if the requested view is not available" do
628
+ allow(helper).to receive(:default_document_index_view_type).and_return(:xyz)
629
+ allow(helper).to receive(:document_index_views).and_return(a: 1, b: 2)
630
+ expect(helper.document_index_view_type(view: :c)).to eq :xyz
631
+ end
632
+
633
+ context "when they have a preferred view" do
634
+ before do
635
+ session[:preferred_view] = :b
636
+ end
637
+
638
+ context "and no view is specified" do
639
+ it "should use the saved preference" do
640
+ allow(helper).to receive(:document_index_views).and_return(a: 1, b: 2, c: 3)
641
+ expect(helper.document_index_view_type).to eq :b
642
+ end
643
+
644
+ it "should use the default view if the preference is not available" do
645
+ allow(helper).to receive(:document_index_views).and_return(a: 1)
646
+ expect(helper.document_index_view_type).to eq :a
647
+ end
648
+ end
649
+
650
+ context "and a view is specified" do
651
+ it "should use the query parameter" do
652
+ allow(helper).to receive(:document_index_views).and_return(a: 1, b: 2, c: 3)
653
+ expect(helper.document_index_view_type(view: :c)).to eq :c
654
+ end
655
+ end
656
+ end
657
+ end
658
+
615
659
  describe "#presenter_class" do
616
660
  before do
617
661
  allow(helper).to receive(:blacklight_config).and_return(blacklight_config)
@@ -150,6 +150,13 @@ describe BlacklightConfigurationHelper do
150
150
 
151
151
  label = helper.solr_field_label :key_a, :key_b, "default text"
152
152
  end
153
+
154
+ it "should compact nil keys (fixes rails/rails#19419)" do
155
+ allow(helper).to receive(:t).with(:key_a, default: [:key_b])
156
+
157
+ label = helper.solr_field_label :key_a, nil, :key_b
158
+
159
+ end
153
160
  end
154
161
 
155
162
  describe "#default_per_page" do
@@ -213,11 +213,25 @@ describe "Blacklight::Configuration" do
213
213
  "another_field_facet" => {},
214
214
  "a_facet_field" => {},
215
215
  })
216
- expect { |b| @config.add_index_field "*_facet", &b }.to yield_control.twice
217
-
218
- expect(@config.index_fields.keys).to eq ["some_field_facet", "another_field_facet"]
216
+ expect { |b| @config.add_facet_field "*_facet", &b }.to yield_control.twice
217
+ expect(@config.facet_fields.keys).to eq ["some_field_facet", "another_field_facet"]
219
218
  end
220
219
 
220
+ describe "if/unless conditions with legacy show parameter" do
221
+ it "should be hidden if the if condition is false" do
222
+ expect(@config.add_facet_field("hidden", if: false).if).to eq false
223
+ expect(@config.add_facet_field("hidden_with_legacy", if: false, show: true).if).to eq false
224
+ end
225
+
226
+ it "should be true if the if condition is true" do
227
+ expect(@config.add_facet_field("hidden", if: true).if).to eq true
228
+ expect(@config.add_facet_field("hidden_with_legacy", if: true, show: false).if).to eq true
229
+ end
230
+
231
+ it "should be true if the if condition is missing" do
232
+ expect(@config.add_facet_field("hidden", show: true).if).to eq true
233
+ end
234
+ end
221
235
  end
222
236
 
223
237
  describe "add_index_field" do
@@ -261,7 +275,6 @@ describe "Blacklight::Configuration" do
261
275
 
262
276
  expect(@config.index_fields.keys).to eq ["some_field_display", "another_field_display"]
263
277
  end
264
-
265
278
  end
266
279
 
267
280
  describe "add_show_field" do
@@ -370,8 +383,22 @@ describe "Blacklight::Configuration" do
370
383
 
371
384
  expect(@config.search_fields["author_name"].label).to eq "Author Name"
372
385
  end
373
-
374
-
386
+
387
+ describe "if/unless conditions with legacy include_in_simple_search" do
388
+ it "should be hidden if the if condition is false" do
389
+ expect(@config.add_search_field("hidden", if: false).if).to eq false
390
+ expect(@config.add_search_field("hidden_with_legacy", if: false, include_in_simple_search: true).if).to eq false
391
+ end
392
+
393
+ it "should be true if the if condition is true" do
394
+ expect(@config.add_search_field("hidden", if: true).if).to eq true
395
+ expect(@config.add_search_field("hidden_with_legacy", if: true, include_in_simple_search: false).if).to eq true
396
+ end
397
+
398
+ it "should be true if the if condition is missing" do
399
+ expect(@config.add_search_field("hidden", include_in_simple_search: true).if).to eq true
400
+ end
401
+ end
375
402
  end
376
403
 
377
404
  describe "add_sort_field" do