blacklight 5.7.2 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -3
  3. data/Gemfile +1 -4
  4. data/VERSION +1 -1
  5. data/app/assets/stylesheets/blacklight/_catalog.css.scss +38 -1
  6. data/app/assets/stylesheets/blacklight/_facets.css.scss +10 -0
  7. data/app/assets/stylesheets/blacklight/_layout.css.scss +6 -0
  8. data/app/controllers/bookmarks_controller.rb +3 -163
  9. data/app/helpers/blacklight/blacklight_helper_behavior.rb +18 -186
  10. data/app/helpers/blacklight/catalog_helper_behavior.rb +36 -2
  11. data/app/helpers/blacklight/component_helper_behavior.rb +77 -0
  12. data/app/helpers/blacklight/configuration_helper_behavior.rb +30 -21
  13. data/app/helpers/blacklight/render_partials_helper.rb +185 -0
  14. data/app/helpers/blacklight/url_helper_behavior.rb +24 -3
  15. data/app/helpers/component_helper.rb +3 -0
  16. data/app/views/_user_util_links.html.erb +2 -15
  17. data/app/views/blacklight/nav/_bookmark.html.erb +4 -0
  18. data/app/views/blacklight/nav/_saved_searches.html.erb +1 -0
  19. data/app/views/blacklight/nav/_search_history.html.erb +1 -0
  20. data/app/views/bookmarks/_tools.html.erb +6 -9
  21. data/app/views/bookmarks/index.html.erb +1 -1
  22. data/app/views/catalog/_bookmark_control.html.erb +8 -8
  23. data/app/views/catalog/_constraints_element.html.erb +1 -1
  24. data/app/views/catalog/_document_action.html.erb +4 -0
  25. data/app/views/catalog/_email_form.html.erb +1 -1
  26. data/app/views/catalog/_facet_limit.html.erb +1 -1
  27. data/app/views/catalog/_index_header_default.html.erb +5 -6
  28. data/app/views/catalog/_per_page_widget.html.erb +3 -1
  29. data/app/views/catalog/_results_pagination.html.erb +1 -1
  30. data/app/views/catalog/_search_form.html.erb +5 -8
  31. data/app/views/catalog/_show_more_like_this.html.erb +2 -2
  32. data/app/views/catalog/_show_tools.html.erb +5 -34
  33. data/app/views/catalog/_sms_form.html.erb +1 -1
  34. data/app/views/catalog/_sort_and_per_page.html.erb +2 -6
  35. data/app/views/catalog/_sort_widget.html.erb +1 -1
  36. data/app/views/catalog/_zero_results.html.erb +2 -2
  37. data/app/views/catalog/citation.js.erb +1 -1
  38. data/app/views/catalog/email_sent.html.erb +2 -9
  39. data/app/views/catalog/email_success.html.erb +9 -0
  40. data/app/views/catalog/sms_sent.html.erb +2 -9
  41. data/app/views/catalog/sms_success.html.erb +9 -0
  42. data/app/views/kaminari/blacklight/_gap.html.erb +1 -1
  43. data/app/views/kaminari/blacklight/_page.html.erb +5 -1
  44. data/app/views/shared/_header_navbar.html.erb +1 -1
  45. data/config/locales/blacklight.en.yml +1 -1
  46. data/config/locales/blacklight.es.yml +1 -1
  47. data/config/locales/blacklight.fr.yml +1 -1
  48. data/config/locales/blacklight.pt-BR.yml +1 -1
  49. data/lib/blacklight.rb +3 -0
  50. data/lib/blacklight/base.rb +0 -1
  51. data/lib/blacklight/bookmarks.rb +135 -0
  52. data/lib/blacklight/catalog.rb +58 -77
  53. data/lib/blacklight/catalog/component_configuration.rb +99 -0
  54. data/lib/blacklight/configuration.rb +82 -4
  55. data/lib/blacklight/configuration/tool_config.rb +4 -0
  56. data/lib/blacklight/controller.rb +5 -1
  57. data/lib/blacklight/document_presenter.rb +17 -8
  58. data/lib/blacklight/request_builders.rb +136 -4
  59. data/lib/blacklight/routes.rb +5 -0
  60. data/lib/blacklight/solr_helper.rb +90 -208
  61. data/lib/blacklight/solr_repository.rb +69 -0
  62. data/lib/blacklight/token_based_user.rb +58 -0
  63. data/lib/blacklight/utils.rb +13 -1
  64. data/lib/generators/blacklight/install_generator.rb +6 -7
  65. data/spec/controllers/alternate_controller_spec.rb +19 -0
  66. data/spec/controllers/catalog_controller_spec.rb +89 -4
  67. data/spec/features/alternate_controller_spec.rb +0 -1
  68. data/spec/features/bookmarks_spec.rb +31 -6
  69. data/spec/features/search_results_spec.rb +11 -0
  70. data/spec/features/search_spec.rb +5 -0
  71. data/spec/helpers/blacklight_helper_spec.rb +49 -8
  72. data/spec/helpers/catalog_helper_spec.rb +56 -8
  73. data/spec/helpers/configuration_helper_spec.rb +5 -5
  74. data/spec/helpers/url_helper_spec.rb +15 -8
  75. data/spec/lib/blacklight/catalog/component_configuration_spec.rb +29 -0
  76. data/spec/lib/blacklight/configuration_spec.rb +15 -0
  77. data/spec/lib/blacklight/solr_helper_spec.rb +44 -104
  78. data/spec/lib/blacklight/solr_repository_spec.rb +113 -0
  79. data/spec/lib/utils_spec.rb +27 -0
  80. data/spec/views/_user_util_links.html.erb_spec.rb +6 -3
  81. data/spec/views/catalog/_show_sidebar.erb_spec.rb +8 -2
  82. data/spec/views/catalog/_show_tools.html.erb_spec.rb +82 -0
  83. data/spec/views/catalog/_sort_and_per_page.html.erb_spec.rb +15 -1
  84. data/tasks/blacklight.rake +25 -1
  85. metadata +24 -2
@@ -5,7 +5,6 @@ module Blacklight::Base
5
5
  include Blacklight::Configurable
6
6
  include Blacklight::SolrHelper
7
7
 
8
- require 'blacklight/catalog/search_context'
9
8
  include Blacklight::Catalog::SearchContext
10
9
 
11
10
  included do
@@ -0,0 +1,135 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # note that while this is mostly restful routing, the #update and #destroy actions
3
+ # take the Solr document ID as the :id, NOT the id of the actual Bookmark action.
4
+ module Blacklight::Bookmarks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ ##
9
+ # Give Bookmarks access to the CatalogController configuration
10
+ include Blacklight::Configurable
11
+ include Blacklight::SolrHelper
12
+ include Blacklight::TokenBasedUser
13
+
14
+ copy_blacklight_config_from(CatalogController)
15
+
16
+ before_filter :verify_user
17
+
18
+ blacklight_config.show.document_actions[:bookmark].if = false if blacklight_config.show.document_actions[:bookmark]
19
+ blacklight_config.show.document_actions[:sms].if = false if blacklight_config.show.document_actions[:sms]
20
+ end
21
+
22
+ def action_documents
23
+ bookmarks = token_or_current_or_guest_user.bookmarks
24
+ bookmark_ids = bookmarks.collect { |b| b.document_id.to_s }
25
+ get_solr_response_for_document_ids(bookmark_ids)
26
+ end
27
+
28
+ def action_success_redirect_path
29
+ bookmarks_path
30
+ end
31
+
32
+ # Blacklight uses #search_action_url to figure out the right URL for
33
+ # the global search box
34
+ def search_action_url *args
35
+ catalog_index_url *args
36
+ end
37
+
38
+ def index
39
+ @bookmarks = token_or_current_or_guest_user.bookmarks
40
+ bookmark_ids = @bookmarks.collect { |b| b.document_id.to_s }
41
+
42
+ @response, @document_list = get_solr_response_for_document_ids(bookmark_ids)
43
+
44
+ respond_to do |format|
45
+ format.html { }
46
+ format.rss { render :layout => false }
47
+ format.atom { render :layout => false }
48
+ format.json do
49
+ render json: render_search_results_as_json
50
+ end
51
+
52
+ additional_response_formats(format)
53
+ document_export_formats(format)
54
+ end
55
+ end
56
+
57
+
58
+ def update
59
+ create
60
+ end
61
+
62
+ # For adding a single bookmark, suggest use PUT/#update to
63
+ # /bookmarks/$docuemnt_id instead.
64
+ # But this method, accessed via POST to /bookmarks, can be used for
65
+ # creating multiple bookmarks at once, by posting with keys
66
+ # such as bookmarks[n][document_id], bookmarks[n][title].
67
+ # It can also be used for creating a single bookmark by including keys
68
+ # bookmark[title] and bookmark[document_id], but in that case #update
69
+ # is simpler.
70
+ def create
71
+ if params[:bookmarks]
72
+ @bookmarks = params[:bookmarks]
73
+ else
74
+ @bookmarks = [{ document_id: params[:id], document_type: blacklight_config.solr_document_model.to_s }]
75
+ end
76
+
77
+ current_or_guest_user.save! unless current_or_guest_user.persisted?
78
+
79
+ success = @bookmarks.all? do |bookmark|
80
+ current_or_guest_user.bookmarks.where(bookmark).exists? || current_or_guest_user.bookmarks.create(bookmark)
81
+ end
82
+
83
+ if request.xhr?
84
+ success ? render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count }}) : render(:text => "", :status => "500")
85
+ else
86
+ if @bookmarks.length > 0 && success
87
+ flash[:notice] = I18n.t('blacklight.bookmarks.add.success', :count => @bookmarks.length)
88
+ elsif @bookmarks.length > 0
89
+ flash[:error] = I18n.t('blacklight.bookmarks.add.failure', :count => @bookmarks.length)
90
+ end
91
+
92
+ redirect_to :back
93
+ end
94
+ end
95
+
96
+ # Beware, :id is the Solr document_id, not the actual Bookmark id.
97
+ # idempotent, as DELETE is supposed to be.
98
+ def destroy
99
+ bookmark = current_or_guest_user.bookmarks.where(document_id: params[:id], document_type: blacklight_config.solr_document_model).first
100
+
101
+ success = bookmark && bookmark.delete && bookmark.destroyed?
102
+
103
+ unless request.xhr?
104
+ if success
105
+ flash[:notice] = I18n.t('blacklight.bookmarks.remove.success')
106
+ else
107
+ flash[:error] = I18n.t('blacklight.bookmarks.remove.failure')
108
+ end
109
+ redirect_to :back
110
+ else
111
+ # ajaxy request needs no redirect and should not have flash set
112
+ success ? render(json: { bookmarks: { count: current_or_guest_user.bookmarks.count }}) : render(:text => "", :status => "500")
113
+ end
114
+ end
115
+
116
+ def clear
117
+ if current_or_guest_user.bookmarks.clear
118
+ flash[:notice] = I18n.t('blacklight.bookmarks.clear.success')
119
+ else
120
+ flash[:error] = I18n.t('blacklight.bookmarks.clear.failure')
121
+ end
122
+ redirect_to :action => "index"
123
+ end
124
+
125
+ protected
126
+ def verify_user
127
+ unless current_or_guest_user or (action == "index" and token_or_current_or_guest_user)
128
+ flash[:notice] = I18n.t('blacklight.bookmarks.need_login') and raise Blacklight::Exceptions::AccessDenied
129
+ end
130
+ end
131
+
132
+ def start_new_search_session?
133
+ action_name == "index"
134
+ end
135
+ end
@@ -1,8 +1,17 @@
1
1
  # -*- encoding : utf-8 -*-
2
- module Blacklight::Catalog
2
+ module Blacklight::Catalog
3
3
  extend ActiveSupport::Concern
4
-
4
+ extend ActiveSupport::Autoload
5
+
6
+ eager_autoload do
7
+ autoload :ComponentConfiguration
8
+ autoload :DocumentActions
9
+ autoload :SearchContext
10
+ end
11
+
5
12
  include Blacklight::Base
13
+ include Blacklight::Catalog::ComponentConfiguration
14
+ include Blacklight::Facet
6
15
 
7
16
  SearchHistoryWindow = 100 # how many searches to save in session history
8
17
 
@@ -18,13 +27,13 @@ module Blacklight::Catalog
18
27
 
19
28
  record_search_parameters
20
29
  end
21
-
30
+
22
31
  # get search results from the solr index
23
32
  def index
24
33
  (@response, @document_list) = get_search_results
25
-
34
+
26
35
  respond_to do |format|
27
- format.html { }
36
+ format.html { preferred_view }
28
37
  format.rss { render :layout => false }
29
38
  format.atom { render :layout => false }
30
39
  format.json do
@@ -35,10 +44,10 @@ module Blacklight::Catalog
35
44
  document_export_formats(format)
36
45
  end
37
46
  end
38
-
47
+
39
48
  # get single document from the solr index
40
49
  def show
41
- @response, @document = get_solr_response_for_doc_id
50
+ @response, @document = get_solr_response_for_doc_id params[:id]
42
51
 
43
52
  respond_to do |format|
44
53
  format.html {setup_next_and_previous_documents}
@@ -49,10 +58,10 @@ module Blacklight::Catalog
49
58
  # export formats.
50
59
  @document.export_formats.each_key do | format_name |
51
60
  # It's important that the argument to send be a symbol;
52
- # if it's a string, it makes Rails unhappy for unclear reasons.
61
+ # if it's a string, it makes Rails unhappy for unclear reasons.
53
62
  format.send(format_name.to_sym) { render :text => @document.export_as(format_name), :layout => false }
54
63
  end
55
-
64
+
56
65
  end
57
66
  end
58
67
 
@@ -80,14 +89,14 @@ module Blacklight::Catalog
80
89
 
81
90
  respond_to do |format|
82
91
  # Draw the facet selector for users who have javascript disabled:
83
- format.html
92
+ format.html
84
93
  format.json { render json: render_facet_list_as_json }
85
94
 
86
95
  # Draw the partial for the "more" facet modal window:
87
96
  format.js { render :layout => false }
88
97
  end
89
98
  end
90
-
99
+
91
100
  # method to serve up XML OpenSearch description and JSON autocomplete response
92
101
  def opensearch
93
102
  respond_to do |format|
@@ -99,72 +108,13 @@ module Blacklight::Catalog
99
108
  end
100
109
  end
101
110
  end
102
-
103
- # citation action
104
- def citation
105
- @response, @documents = get_solr_response_for_document_ids(params[:id])
106
- respond_to do |format|
107
- format.html
108
- format.js { render :layout => false }
109
- end
110
- end
111
-
112
-
113
- # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
114
- def email
115
- @response, @documents = get_solr_response_for_document_ids(params[:id])
116
-
117
- if request.post? and validate_email_params
118
- email = RecordMailer.email_record(@documents, {:to => params[:to], :message => params[:message]}, url_options)
119
-
120
- if email.respond_to? :deliver_now
121
- email.deliver_now
122
- else
123
- email.deliver
124
- end
125
-
126
- flash[:success] = I18n.t("blacklight.email.success")
127
-
128
- respond_to do |format|
129
- format.html { redirect_to catalog_path(params['id']) }
130
- format.js { render 'email_sent' }
131
- end and return
132
- end
133
111
 
134
- respond_to do |format|
135
- format.html
136
- format.js { render :layout => false }
137
- end
112
+ def action_documents
113
+ get_solr_response_for_document_ids(params[:id])
138
114
  end
139
115
 
140
-
141
- # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
142
- def sms
143
- @response, @documents = get_solr_response_for_document_ids(params[:id])
144
-
145
- if request.post? and validate_sms_params
146
- to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
147
-
148
- sms = RecordMailer.sms_record(@documents, { :to => to }, url_options)
149
-
150
- if sms.respond_to? :deliver_now
151
- sms.deliver_now
152
- else
153
- sms.deliver
154
- end
155
-
156
- flash[:success] = I18n.t("blacklight.sms.success")
157
-
158
- respond_to do |format|
159
- format.html { redirect_to catalog_path(params['id']) }
160
- format.js { render 'sms_sent' }
161
- end and return
162
- end
163
-
164
- respond_to do |format|
165
- format.js { render :layout => false }
166
- format.html
167
- end
116
+ def action_success_redirect_path
117
+ catalog_path(params[:id])
168
118
  end
169
119
 
170
120
  ##
@@ -173,12 +123,22 @@ module Blacklight::Catalog
173
123
  def has_search_parameters?
174
124
  !params[:q].blank? or !params[:f].blank? or !params[:search_field].blank?
175
125
  end
176
-
177
- protected
126
+
127
+ protected
178
128
  #
179
129
  # non-routable methods ->
180
130
  #
181
131
 
132
+ ##
133
+ # If the params specify a view, then store it in the session. If the params
134
+ # do not specifiy the view, set the view parameter to the value stored in the
135
+ # session. This enables a user with a session to do subsequent searches and have
136
+ # them default to the last used view.
137
+ def preferred_view
138
+ session[:preferred_view] = params[:view] if params[:view]
139
+ params[:view] ||= session[:preferred_view]
140
+ end
141
+
182
142
  ##
183
143
  # Render additional response formats, as provided by the blacklight configuration
184
144
  def additional_response_formats format
@@ -265,7 +225,28 @@ module Blacklight::Catalog
265
225
 
266
226
  h
267
227
  end
268
-
228
+
229
+ # Email Action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
230
+ def email_action documents
231
+ mail = RecordMailer.email_record(documents, {:to => params[:to], :message => params[:message]}, url_options)
232
+ if mail.respond_to? :deliver_now
233
+ mail.deliver_now
234
+ else
235
+ mail.deliver
236
+ end
237
+ end
238
+
239
+ # SMS action (this will render the appropriate view on GET requests and process the form and send the email on POST requests)
240
+ def sms_action documents
241
+ to = "#{params[:to].gsub(/[^\d]/, '')}@#{params[:carrier]}"
242
+ mail = RecordMailer.sms_record(documents, { :to => to }, url_options)
243
+ if mail.respond_to? :deliver_now
244
+ mail.deliver_now
245
+ else
246
+ mail.deliver
247
+ end
248
+ end
249
+
269
250
  def validate_sms_params
270
251
  case
271
252
  when params[:to].blank?
@@ -0,0 +1,99 @@
1
+ module Blacklight
2
+ module Catalog::ComponentConfiguration
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ add_results_document_tool(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
7
+
8
+ add_results_collection_tool(:sort_widget)
9
+ add_results_collection_tool(:per_page_widget)
10
+ add_results_collection_tool(:view_type_group)
11
+
12
+ add_show_tools_partial(:bookmark, partial: 'bookmark_control', if: :render_bookmarks_control?)
13
+ add_show_tools_partial(:refworks, if: :render_refworks_action?)
14
+ add_show_tools_partial(:endnote, if: :render_endnote_action? )
15
+ add_show_tools_partial(:email, callback: :email_action, validator: :validate_email_params)
16
+ add_show_tools_partial(:sms, callback: :sms_action, validator: :validate_sms_params)
17
+ add_show_tools_partial(:citation)
18
+ add_show_tools_partial(:librarian_view, if: :render_librarian_view_control?)
19
+
20
+ add_nav_action(:bookmark, partial: 'blacklight/nav/bookmark', if: :render_bookmarks_control?)
21
+ add_nav_action(:saved_searches, partial: 'blacklight/nav/saved_searches', if: :render_saved_searches?)
22
+ add_nav_action(:search_history, partial: 'blacklight/nav/search_history')
23
+ end
24
+
25
+ module ClassMethods
26
+
27
+ ##
28
+ # Add a partial to the tools for rendering a document
29
+ # @param partial [String] the name of the document partial
30
+ # @param opts [Hash]
31
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
32
+ # The proc will receive the action configuration and the document or documents for the action.
33
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
34
+ # The proc will receive the action configuration and the document or documents for the action.
35
+ def add_show_tools_partial name, opts = {}
36
+ blacklight_config.add_show_tools_partial(name, opts)
37
+
38
+ define_method name do
39
+ @response, @documents = action_documents
40
+
41
+ if request.post? and
42
+ opts[:callback] and
43
+ (opts[:validator].blank? || self.send(opts[:validator]))
44
+
45
+ self.send(opts[:callback], @documents)
46
+
47
+ flash[:success] ||= I18n.t("blacklight.#{name}.success", default: nil)
48
+
49
+ respond_to do |format|
50
+ format.html { redirect_to action_success_redirect_path }
51
+ format.js { render "#{name}_success" }
52
+ end
53
+ else
54
+ respond_to do |format|
55
+ format.html
56
+ format.js { render :layout => false }
57
+ end
58
+ end
59
+ end unless method_defined? name
60
+ end
61
+
62
+ ##
63
+ # Add a tool to be displayed for each document in the search results.
64
+ # @param partial [String] the name of the document partial
65
+ # @param opts [Hash]
66
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
67
+ # The proc will receive the action configuration and the document or documents for the action.
68
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
69
+ # The proc will receive the action configuration and the document or documents for the action.
70
+ def add_results_document_tool name, opts = {}
71
+ blacklight_config.add_results_document_tool(name, opts)
72
+ end
73
+
74
+ ##
75
+ # Add a tool to be displayed for the list of search results themselves.
76
+ # @param partial [String] the name of the document partial
77
+ # @param opts [Hash]
78
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
79
+ # The proc will receive the action configuration and the document or documents for the action.
80
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
81
+ # The proc will receive the action configuration and the document or documents for the action.
82
+ def add_results_collection_tool name, opts = {}
83
+ blacklight_config.add_results_collection_tool(name, opts)
84
+ end
85
+
86
+ ##
87
+ # Add a partial to the header navbar
88
+ # @param partial [String] the name of the document partial
89
+ # @param opts [Hash]
90
+ # @option opts [Symbol,Proc] :if render this action if the method identified by the symbol or the proc evaluates to true.
91
+ # The proc will receive the action configuration and the document or documents for the action.
92
+ # @option opts [Symbol,Proc] :unless render this action unless the method identified by the symbol or the proc evaluates to true
93
+ # The proc will receive the action configuration and the document or documents for the action.
94
+ def add_nav_action name, opts = {}
95
+ blacklight_config.add_nav_action(name, opts)
96
+ end
97
+ end
98
+ end
99
+ end