blacklight 5.3.0 → 5.4.0.rc1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/VERSION +1 -1
  4. data/app/assets/javascripts/blacklight/blacklight.js +1 -0
  5. data/app/assets/javascripts/blacklight/collapsable.js +9 -0
  6. data/app/controllers/bookmarks_controller.rb +72 -9
  7. data/app/helpers/blacklight/blacklight_helper_behavior.rb +15 -7
  8. data/app/helpers/blacklight/catalog_helper_behavior.rb +17 -9
  9. data/app/helpers/blacklight/configuration_helper_behavior.rb +59 -7
  10. data/app/helpers/blacklight/facets_helper_behavior.rb +1 -16
  11. data/app/helpers/blacklight/url_helper_behavior.rb +21 -2
  12. data/app/models/bookmark.rb +13 -4
  13. data/app/models/solr_document.rb +5 -0
  14. data/app/views/bookmarks/_tools.html.erb +10 -11
  15. data/app/views/catalog/_bookmark_control.html.erb +2 -2
  16. data/app/views/catalog/_refworks_form.html.erb +3 -2
  17. data/app/views/catalog/_sort_widget.html.erb +5 -5
  18. data/app/views/catalog/_view_type_group.html.erb +2 -2
  19. data/app/views/shared/_header_navbar.html.erb +1 -3
  20. data/config/locales/blacklight.pt-BR.yml +223 -0
  21. data/db/migrate/20140320000000_add_polymorphic_type_to_bookmarks.rb +8 -0
  22. data/gemfiles/rails4.1.gemfile +1 -1
  23. data/lib/blacklight.rb +5 -0
  24. data/lib/blacklight/catalog.rb +33 -5
  25. data/lib/blacklight/configuration.rb +12 -3
  26. data/lib/blacklight/configuration/facet_field.rb +1 -1
  27. data/lib/blacklight/configuration/search_field.rb +3 -2
  28. data/lib/blacklight/configuration/solr_field.rb +2 -1
  29. data/lib/blacklight/configuration/sort_field.rb +2 -1
  30. data/lib/blacklight/engine.rb +9 -1
  31. data/lib/blacklight/exceptions.rb +3 -0
  32. data/lib/blacklight/rails/routes.rb +12 -0
  33. data/lib/blacklight/request_builders.rb +19 -18
  34. data/lib/blacklight/search_fields.rb +0 -9
  35. data/lib/blacklight/solr/document.rb +15 -0
  36. data/lib/blacklight/solr/document/export.rb +4 -0
  37. data/lib/blacklight/solr_helper.rb +25 -28
  38. data/lib/blacklight/solr_response.rb +31 -29
  39. data/lib/blacklight/solr_response/response.rb +18 -0
  40. data/lib/blacklight/user.rb +17 -4
  41. data/lib/blacklight/utils.rb +30 -2
  42. data/lib/generators/blacklight/install_generator.rb +4 -0
  43. data/lib/generators/blacklight/templates/config/initializers/blacklight_initializer.rb +9 -0
  44. data/spec/controllers/application_controller_spec.rb +0 -1
  45. data/spec/controllers/bookmarks_controller_spec.rb +8 -4
  46. data/spec/controllers/catalog_controller_spec.rb +48 -55
  47. data/spec/controllers/saved_searches_controller_spec.rb +1 -4
  48. data/spec/controllers/search_history_controller_spec.rb +0 -1
  49. data/spec/features/bookmarks_spec.rb +14 -0
  50. data/spec/features/search_formats_spec.rb +45 -0
  51. data/spec/helpers/blacklight_helper_spec.rb +71 -30
  52. data/spec/helpers/configuration_helper_spec.rb +128 -4
  53. data/spec/helpers/facets_helper_spec.rb +1 -1
  54. data/spec/lib/blacklight/configuration_spec.rb +0 -5
  55. data/spec/lib/blacklight/search_fields_spec.rb +0 -22
  56. data/spec/lib/blacklight/solr/document_spec.rb +6 -0
  57. data/spec/lib/blacklight/solr_helper_spec.rb +31 -10
  58. data/spec/lib/blacklight/solr_response_spec.rb +8 -0
  59. data/spec/lib/blacklight/user_spec.rb +38 -4
  60. data/spec/models/bookmark_spec.rb +22 -17
  61. data/spec/spec_helper.rb +2 -0
  62. data/template.demo.rb +4 -9
  63. metadata +12 -6
  64. data/spec/data/sample_docs.yml +0 -655
@@ -0,0 +1,18 @@
1
+ module Blacklight::SolrResponse::Response
2
+ def response
3
+ self[:response] || {}
4
+ end
5
+
6
+ # short cut to response['numFound']
7
+ def total
8
+ response[:numFound].to_s.to_i
9
+ end
10
+
11
+ def start
12
+ response[:start].to_s.to_i
13
+ end
14
+
15
+ def empty?
16
+ total == 0
17
+ end
18
+ end
@@ -1,5 +1,8 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Blacklight::User
3
+
4
+ extend Deprecation
5
+ self.deprecation_horizon = 'blacklight 6.0'
3
6
 
4
7
  # This gives us an is_blacklight_user method that can be included in
5
8
  # the containing applications models.
@@ -12,17 +15,27 @@ module Blacklight::User
12
15
  end
13
16
  end
14
17
 
18
+ def bookmarks_for_documents documents = []
19
+ if documents.length > 0
20
+ bookmarks.where(document_type: documents.first.class.base_class, document_id: documents.map { |x| x.id})
21
+ else
22
+ []
23
+ end
24
+ end
25
+
15
26
  def bookmarked_document_ids
27
+ Deprecation.warn self, "The User#bookmarked_document_ids method is deprecated and will be removed in Blacklight 6.0"
28
+
16
29
  self.bookmarks.pluck(:document_id)
17
30
  end
18
31
 
19
- def document_is_bookmarked?(document_id)
20
- bookmarked_document_ids.include? document_id.to_s
32
+ def document_is_bookmarked?(document)
33
+ bookmarks_for_documents([document]).any?
21
34
  end
22
35
 
23
36
  # returns a Bookmark object if there is one for document_id, else
24
37
  # nil.
25
- def existing_bookmark_for(document_id)
26
- self.bookmarks.where(:document_id => document_id).first
38
+ def existing_bookmark_for(document)
39
+ bookmarks_for_documents([document]).first
27
40
  end
28
41
  end
@@ -21,6 +21,10 @@ module Blacklight
21
21
  def to_h
22
22
  @table
23
23
  end
24
+
25
+ def select *args, &block
26
+ self.class.new to_h.select(*args, &block)
27
+ end
24
28
 
25
29
  ##
26
30
  # Merge the values of this OpenStruct with another OpenStruct or Hash
@@ -54,7 +58,7 @@ module Blacklight
54
58
  hashes_and_keys = args.flatten
55
59
  lazy_configs = hashes_and_keys.extract_options!
56
60
 
57
- args.each do |v|
61
+ hashes_and_keys.each do |v|
58
62
  if v.is_a? Hash
59
63
  key = v.first
60
64
  value = v[key]
@@ -66,7 +70,11 @@ module Blacklight
66
70
  end
67
71
 
68
72
  lazy_configs.each do |k,v|
69
- hash[k] = nested_class.new v
73
+ if v.is_a? nested_class
74
+ hash[k] = v
75
+ else
76
+ hash[k] = nested_class.new v
77
+ end
70
78
  end
71
79
 
72
80
  super hash
@@ -111,6 +119,26 @@ module Blacklight
111
119
  set_default_proc!
112
120
  end
113
121
 
122
+ def select *args, &block
123
+ self.class.new nested_class, to_h.select(*args, &block)
124
+ end
125
+
126
+ ##
127
+ # Merge the values of this OpenStruct with another OpenStruct or Hash
128
+ # @param [Hash,#to_h]
129
+ # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess
130
+ def merge other_hash
131
+ self.class.new nested_class, to_h.merge((other_hash if other_hash.is_a? Hash) || other_hash.to_h)
132
+ end
133
+
134
+ ##
135
+ # Merge the values of another OpenStruct or Hash into this object
136
+ # @param [Hash,#to_h]
137
+ # @return [OpenStructWithHashAccess] a new instance of an OpenStructWithHashAccess
138
+ def merge! other_hash
139
+ @table.merge!(nested_class, (other_hash if other_hash.is_a? Hash) || other_hash.to_h)
140
+ end
141
+
114
142
  private
115
143
  def set_default_proc!
116
144
  self.default_proc = lambda do |hash, key|
@@ -104,5 +104,9 @@ EOF
104
104
  def inject_blacklight_i18n_strings
105
105
  copy_file "blacklight.en.yml", "config/locales/blacklight.en.yml"
106
106
  end
107
+
108
+ def add_blacklight_initializer
109
+ template "config/initializers/blacklight_initializer.rb"
110
+ end
107
111
  end
108
112
  end
@@ -0,0 +1,9 @@
1
+ # A secret token used to encrypt user_id's in the Bookmarks#export callback URL
2
+ # functionality, for example in Refworks export of Bookmarks. In Rails 4, Blacklight
3
+ # will use the application's secret key base instead.
4
+ #
5
+ <% if Rails::VERSION::MAJOR == 4 %>
6
+ # Blacklight.secret_key = '<%= SecureRandom.hex(64) %>'
7
+ <% else %>
8
+ Blacklight.secret_key = '<%= SecureRandom.hex(64) %>'
9
+ <% end %>
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ApplicationController do
4
- include Devise::TestHelpers
5
4
 
6
5
  describe "#blacklight_config" do
7
6
 
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe BookmarksController do
4
- include Devise::TestHelpers
5
-
6
4
  # jquery 1.9 ajax does error callback if 200 returns empty body. so use 204 instead.
7
5
  describe "update" do
8
6
  it "has a 204 status code when creating a new one" do
@@ -14,6 +12,7 @@ describe BookmarksController do
14
12
  it "has a 500 status code when fails is success" do
15
13
  @controller.stub_chain(:current_or_guest_user, :existing_bookmark_for).and_return(false)
16
14
  @controller.stub_chain(:current_or_guest_user, :persisted?).and_return(true)
15
+ @controller.stub_chain(:current_or_guest_user, :bookmarks, :where, :exists?).and_return(false)
17
16
  @controller.stub_chain(:current_or_guest_user, :bookmarks, :create).and_return(false)
18
17
  xhr :put, :update, :id => 'iamabooboo', :format => :js
19
18
  expect(response.code).to eq "500"
@@ -21,6 +20,11 @@ describe BookmarksController do
21
20
  end
22
21
 
23
22
  describe "delete" do
23
+ before do
24
+ @controller.send(:current_or_guest_user).save
25
+ @controller.send(:current_or_guest_user).bookmarks.create! document_id: '2007020969', document_type: "SolrDocument"
26
+ end
27
+
24
28
  it "has a 204 status code when delete is success" do
25
29
  xhr :delete, :destroy, :id => '2007020969', :format => :js
26
30
  expect(response).to be_success
@@ -30,7 +34,7 @@ describe BookmarksController do
30
34
  it "has a 500 status code when delete is not success" do
31
35
  bm = double(Bookmark)
32
36
  @controller.stub_chain(:current_or_guest_user, :existing_bookmark_for).and_return(bm)
33
- @controller.stub_chain(:current_or_guest_user, :bookmarks, :delete).and_return(false)
37
+ @controller.stub_chain(:current_or_guest_user, :bookmarks, :where, :first).and_return(double('bookmark', delete: nil, destroyed?: false))
34
38
 
35
39
  xhr :delete, :destroy, :id => 'pleasekillme', :format => :js
36
40
 
@@ -38,4 +42,4 @@ describe BookmarksController do
38
42
  end
39
43
  end
40
44
 
41
- end
45
+ end
@@ -1,24 +1,26 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CatalogController do
4
- include Devise::TestHelpers
5
- # INDEX ACTION
4
+
6
5
  describe "index action" do
7
- before(:each) do
8
- @user_query = 'history' # query that will get results
9
- @no_docs_query = 'sadfdsafasdfsadfsadfsadf' # query for no results
10
- @facet_query = {"format" => 'Book'}
11
- end
12
6
 
13
- # in rails3, the assigns method within ActionDispathc::TestProcess
14
- # kindly converts anything that desends from hash to a hash_With_indifferent_access
15
- # which means that our solr resposne object gets replaced if we call
16
- # assigns(:response) - so we can't do that anymore.
17
- def assigns_response
18
- @controller.instance_variable_get("@response")
7
+ # In Rails 3 ActionDispatch::TestProcess#assigns() converts anything that
8
+ # descends from Hash to a HashWithIndifferentAccess. Therefore our Solr
9
+ # response object gets replaced if we call assigns(:response)
10
+ # Fixed by https://github.com/rails/rails/commit/185c3dbc6ab845edfc94e8d38ef5be11c417dd81
11
+ if ::Rails.version < "4.0"
12
+ def assigns_response
13
+ controller.instance_variable_get("@response")
14
+ end
15
+ else
16
+ def assigns_response
17
+ assigns(:response)
18
+ end
19
19
  end
20
20
 
21
21
  describe "with format :html" do
22
+ let(:user_query) { 'history' } # query that will get results
23
+
22
24
  it "should have no search history if no search criteria" do
23
25
  controller.should_receive(:get_search_results)
24
26
  session[:history] = []
@@ -28,12 +30,12 @@ describe CatalogController do
28
30
 
29
31
  # check each user manipulated parameter
30
32
  it "should have docs and facets for query with results", :integration => true do
31
- get :index, :q => @user_query
33
+ get :index, q: user_query
32
34
  expect(assigns_response.docs).to_not be_empty
33
35
  assert_facets_have_values(assigns_response.facets)
34
36
  end
35
37
  it "should have docs and facets for existing facet value", :integration => true do
36
- get :index, :f => @facet_query
38
+ get :index, f: {"format" => 'Book'}
37
39
  expect(assigns_response.docs).to_not be_empty
38
40
  assert_facets_have_values(assigns_response.facets)
39
41
  end
@@ -53,7 +55,7 @@ describe CatalogController do
53
55
  end
54
56
 
55
57
  it "should have no docs or facet values for query without results", :integration => true do
56
- get :index, :q => @no_docs_query
58
+ get :index, q: 'sadfdsafasdfsadfsadfsadf' # query for no results
57
59
 
58
60
  expect(assigns_response.docs).to be_empty
59
61
  assigns_response.facets.each do |facet|
@@ -71,12 +73,12 @@ describe CatalogController do
71
73
  controller.stub(:get_search_results)
72
74
  end
73
75
  it "should include search hash with key :q" do
74
- get :index, :q => @user_query
76
+ get :index, q: user_query
75
77
  expect(session[:search]).to_not be_nil
76
78
  expect(session[:search].keys).to include 'id'
77
79
 
78
80
  search = Search.find(session[:search]['id'])
79
- expect(search.query_params['q']).to eq @user_query
81
+ expect(search.query_params['q']).to eq user_query
80
82
  end
81
83
  end
82
84
 
@@ -295,8 +297,7 @@ describe CatalogController do
295
297
  @mock_response = double()
296
298
  @mock_document = double()
297
299
  @mock_document.stub(:export_formats => {})
298
- controller.stub(:get_solr_response_for_doc_id => [@mock_response, @mock_document],
299
- :get_single_doc_via_search => @mock_document)
300
+ controller.stub(:get_solr_response_for_doc_id => [@mock_response, @mock_document])
300
301
  get :show, :id => doc_id
301
302
  response.should render_template(:show)
302
303
  end
@@ -304,10 +305,9 @@ describe CatalogController do
304
305
  describe "@document" do
305
306
  before do
306
307
  @mock_response = double()
307
- @mock_response.stub(:docs => [{ :id => 'my_fake_doc' }])
308
+ @mock_response.stub(documents: [SolrDocument.new(id: 'my_fake_doc')])
308
309
  @mock_document = double()
309
- controller.stub(:find => @mock_response,
310
- :get_single_doc_via_search => @mock_document)
310
+ controller.stub(:find => @mock_response )
311
311
  end
312
312
  before(:each) do
313
313
  get :show, :id => doc_id
@@ -329,18 +329,15 @@ describe CatalogController do
329
329
  "mock_export"
330
330
  end
331
331
  end
332
+
332
333
  before do
333
334
  @mock_response = double()
334
335
  @mock_response.stub(:docs => [{ :id => 'my_fake_doc' }])
335
336
  @mock_document = double()
336
- controller.stub(:find => @mock_response,
337
- :get_single_doc_via_search => @mock_document)
338
-
339
- controller.stub(:find => @mock_response,
340
- :get_single_doc_via_search => @mock_document)
337
+ controller.stub(find: @mock_response)
341
338
  end
342
339
 
343
- before(:each) do
340
+ before(:each) do
344
341
 
345
342
  # Rails3 needs this to propertly setup a new mime type and
346
343
  # render the results.
@@ -352,8 +349,19 @@ describe CatalogController do
352
349
  SolrDocument.use_extension(FakeExtension)
353
350
  end
354
351
 
352
+ before do
353
+ @mock_response = double()
354
+ @mock_response.stub(:documents => [SolrDocument.new(id: 'my_fake_doc')])
355
+ @mock_document = double()
356
+ controller.stub(:find => @mock_response,
357
+ :get_single_doc_via_search => @mock_document)
358
+
359
+ controller.stub(:find => @mock_response,
360
+ :get_single_doc_via_search => @mock_document)
361
+ end
362
+
355
363
  it "should respond to an extension-registered format properly" do
356
- get :show, :id => doc_id, :format => "mock" # This no longer works: :format => "mock"
364
+ get :show, :id => doc_id, :format => "mock"
357
365
  expect(response).to be_success
358
366
  expect(response.body).to match /mock_export/
359
367
  end
@@ -371,10 +379,10 @@ describe CatalogController do
371
379
  before do
372
380
  @mock_response = double()
373
381
  @mock_document = double()
374
- @mock_response.stub(:docs => [{ :id => 'my_fake_doc' }, { :id => 'my_other_doc'}])
382
+ @mock_response.stub(documents: [SolrDocument.new(id: 'my_fake_doc'), SolrDocument.new(id: 'my_other_doc')])
375
383
  @mock_document = double()
376
- controller.stub(:find => @mock_response,
377
- :get_single_doc_via_search => @mock_document)
384
+ controller.stub(find: @mock_response)
385
+
378
386
  end
379
387
  it "should return an opensearch description" do
380
388
  get :opensearch, :format => 'xml'
@@ -388,15 +396,9 @@ describe CatalogController do
388
396
 
389
397
  describe "email/sms" do
390
398
  doc_id = '2007020969'
391
- before do
392
- @mock_response = double()
393
- @mock_document = double()
394
- @mock_response.stub(:docs => [{ :id => 'my_fake_doc' }, { :id => 'my_other_doc'}])
395
- @mock_document = double()
396
- controller.stub(:find => @mock_response,
397
- :get_single_doc_via_search => @mock_document)
398
- end
399
- before(:each) do
399
+ let(:mock_response) { double(documents: [SolrDocument.new(id: 'my_fake_doc'), SolrDocument.new(id: 'my_other_doc')]) }
400
+ before do
401
+ controller.stub(find: mock_response)
400
402
  request.env["HTTP_REFERER"] = "/catalog/#{doc_id}"
401
403
  SolrDocument.use_extension( Blacklight::Solr::Document::Email )
402
404
  SolrDocument.use_extension( Blacklight::Solr::Document::Sms )
@@ -468,21 +470,15 @@ describe CatalogController do
468
470
 
469
471
  describe "errors" do
470
472
  it "should return status 404 for a record that doesn't exist" do
471
- @mock_response = double()
472
- @mock_response.stub(:docs => [])
473
- @mock_document = double()
474
- controller.stub(:find => @mock_response,
475
- :get_single_doc_via_search => @mock_document)
473
+ @mock_response = double(documents: [])
474
+ controller.stub(:find => @mock_response)
476
475
  get :show, :id=>"987654321"
477
476
  expect(response.status).to eq 404
478
477
  expect(response.content_type).to eq Mime::HTML
479
478
  end
480
479
  it "should return status 404 for a record that doesn't exist even for non-html format" do
481
- @mock_response = double()
482
- @mock_response.stub(:docs => [])
483
- @mock_document = double()
484
- controller.stub(:find => @mock_response,
485
- :get_single_doc_via_search => @mock_document)
480
+ @mock_response = double(documents: [])
481
+ controller.stub(:find => @mock_response)
486
482
 
487
483
  get :show, :id=>"987654321", :format => "xml"
488
484
  expect(response.status).to eq 404
@@ -523,9 +519,6 @@ describe CatalogController do
523
519
 
524
520
  before do
525
521
  controller.stub(:has_user_authentication_provider?) { false }
526
- @mock_response = double()
527
- @mock_document = double()
528
- controller.stub(:get_single_doc_via_search => @mock_document)
529
522
  end
530
523
 
531
524
  it "should not show user util links" do
@@ -1,14 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SavedSearchesController do
4
- include Devise::TestHelpers
5
4
 
6
5
  before(:all) do
7
6
  @one = Search.create
8
7
  @two = Search.create
9
8
  @three = Search.create
10
-
11
-
12
9
  end
13
10
 
14
11
  before(:each) do
@@ -36,4 +33,4 @@ describe SavedSearchesController do
36
33
 
37
34
 
38
35
 
39
- end
36
+ end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SearchHistoryController do
4
- include Devise::TestHelpers
5
4
 
6
5
  describe "index" do
7
6
  before(:all) do
@@ -55,4 +55,18 @@ describe "Bookmarks" do
55
55
  click_link 'Cite'
56
56
  expect(page).to have_content 'Strong Medicine speaks'
57
57
  end
58
+
59
+ it "should have an endnote export" do
60
+ visit catalog_path('2007020969')
61
+ click_button 'Bookmark'
62
+ visit "/bookmarks.endnote?q="
63
+ expect(page).to have_content " %@ 9780743297790"
64
+ end
65
+
66
+ it "should have a refworks export" do
67
+ visit catalog_path('2007020969')
68
+ click_button 'Bookmark'
69
+ visit "/bookmarks.refworks_marc_txt?q="
70
+ expect(page).to have_content "LEADER 01490cam a2200361 a 4500001 2007020969"
71
+ end
58
72
  end