blacklight 3.6.1.1 → 3.7.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 (32) hide show
  1. data/VERSION +1 -1
  2. data/app/controllers/bookmarks_controller.rb +28 -46
  3. data/app/helpers/blacklight/blacklight_helper_behavior.rb +4 -11
  4. data/app/helpers/blacklight/facets_helper_behavior.rb +57 -4
  5. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +4 -1
  6. data/app/helpers/blacklight/search_history_constraints_helper_behavior.rb +5 -3
  7. data/app/views/_user_util_links.html.erb +8 -7
  8. data/app/views/bookmarks/index.html.erb +1 -1
  9. data/app/views/catalog/_bookmark_control.html.erb +2 -2
  10. data/lib/blacklight/configuration.rb +14 -1
  11. data/lib/blacklight/configuration/facet_field.rb +14 -0
  12. data/lib/blacklight/controller.rb +44 -7
  13. data/lib/blacklight/routes.rb +1 -10
  14. data/lib/blacklight/solr_helper.rb +60 -17
  15. data/lib/generators/blacklight/blacklight_generator.rb +1 -0
  16. data/lib/generators/blacklight/templates/catalog_controller.rb +11 -6
  17. data/test_support/bin/test.sh +1 -0
  18. data/test_support/features/bookmarks.feature +9 -19
  19. data/test_support/spec/controllers/application_controller_spec.rb +1 -0
  20. data/test_support/spec/controllers/bookmarks_controller_spec.rb +48 -0
  21. data/test_support/spec/controllers/catalog_controller_spec.rb +2 -1
  22. data/test_support/spec/controllers/search_history_controller_spec.rb +2 -0
  23. data/test_support/spec/helpers/blacklight_helper_spec.rb +1 -2
  24. data/test_support/spec/helpers/facets_helper_spec.rb +91 -4
  25. data/test_support/spec/helpers/search_history_constraints_helper_spec.rb +3 -0
  26. data/test_support/spec/lib/solr_helper_spec.rb +56 -8
  27. metadata +6 -9
  28. data/app/controllers/folder_controller.rb +0 -54
  29. data/app/views/catalog/_folder_control.html.erb +0 -12
  30. data/test_support/features/folder.feature +0 -67
  31. data/test_support/features/step_definitions/folder_steps.rb +0 -27
  32. data/test_support/spec/controllers/folder_controller_spec.rb +0 -47
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.6.1.1
1
+ 3.7.0
@@ -3,40 +3,14 @@
3
3
  # take the Solr document ID as the :id, NOT the id of the actual Bookmark action.
4
4
  class BookmarksController < ApplicationController
5
5
 
6
- before_filter :require_user_authentication_provider
7
6
  before_filter :verify_user
8
-
9
- # Beware, :id is the Solr document_id, not the actual Bookmark id.
10
- # idempotent, as PUT is supposed to be.
11
- # you can also send a bookmark[title] param, which will be used for simplest case
12
- # or fall through display of Bookmark in list.
13
- def update
14
- bookmark = current_user.existing_bookmark_for(params[:id])
15
- if bookmark
16
- #update existing one with new values if present
17
- bookmark.attributes = params[:bookmark] if params[:bookmark]
18
- else
19
- # create new one with values and document_id
20
- bookmark = current_user.bookmarks.build(params[:bookmark].merge(:document_id => params[:id]))
21
- end
22
-
23
- success = bookmark.save
24
-
25
- unless request.xhr?
26
- if success
27
- flash[:notice] = I18n.t('blacklight.bookmarks.add.success')
28
- else
29
- flash[:error] = I18n.t('blacklight.bookmarks.add.failure')
30
- end
31
- redirect_to :back
32
- else
33
- #ajaxy request doesn't need a redirect and shouldn't have flash set
34
- render :text => "", :status => (success ? "200" : "500" )
35
- end
36
- end
37
7
 
38
8
  def index
39
- @bookmarks = current_user.bookmarks.page(params[:page])
9
+ @bookmarks = current_or_guest_user.bookmarks.page(params[:page])
10
+ end
11
+
12
+ def update
13
+ create
40
14
  end
41
15
 
42
16
  # For adding a single bookmark, suggest use PUT/#update to
@@ -49,27 +23,35 @@ class BookmarksController < ApplicationController
49
23
  # is simpler.
50
24
  def create
51
25
  @bookmarks = params[:bookmarks] || []
52
- @bookmarks << params[:bookmark] if params[:bookmark]
53
-
54
- success = true
55
- @bookmarks.each do |key, bookmark|
56
- success = false unless current_user.bookmarks.create(bookmark)
26
+
27
+ if params[:bookmark]
28
+ params[:bookmark][:document_id] ||= params[:id]
29
+ @bookmarks << params[:bookmark] if params[:bookmark]
30
+ end
31
+
32
+ success = @bookmarks.all? do |bookmark|
33
+ current_or_guest_user.bookmarks.create(bookmark) unless current_or_guest_user.existing_bookmark_for(bookmark[:document_id])
57
34
  end
58
- if @bookmarks.length > 0 && success
59
- flash[:notice] = I18n.t('blacklight.bookmarks.add.success', :count => @bookmarks.length)
60
- elsif @bookmarks.length > 0
61
- flash[:error] = I18n.t('blacklight.bookmarks.add.failure', :count => @bookmarks.length)
35
+
36
+ if request.xhr?
37
+ render :text => "", :status => (success ? "200" : "500" )
38
+ else
39
+ if @bookmarks.length > 0 && success
40
+ flash[:notice] = I18n.t('blacklight.bookmarks.add.success', :count => @bookmarks.length)
41
+ elsif @bookmarks.length > 0
42
+ flash[:error] = I18n.t('blacklight.bookmarks.add.failure', :count => @bookmarks.length)
43
+ end
44
+
45
+ redirect_to :back
62
46
  end
63
-
64
- redirect_to :back
65
47
  end
66
48
 
67
49
  # Beware, :id is the Solr document_id, not the actual Bookmark id.
68
50
  # idempotent, as DELETE is supposed to be.
69
51
  def destroy
70
- bookmark = current_user.existing_bookmark_for(params[:id])
52
+ bookmark = current_or_guest_user.existing_bookmark_for(params[:id])
71
53
 
72
- success = (!bookmark) || current_user.bookmarks.delete(bookmark)
54
+ success = (!bookmark) || current_or_guest_user.bookmarks.delete(bookmark)
73
55
 
74
56
  unless request.xhr?
75
57
  if success
@@ -85,7 +67,7 @@ class BookmarksController < ApplicationController
85
67
  end
86
68
 
87
69
  def clear
88
- if current_user.bookmarks.clear
70
+ if current_or_guest_user.bookmarks.clear
89
71
  flash[:notice] = I18n.t('blacklight.bookmarks.clear.success')
90
72
  else
91
73
  flash[:error] = I18n.t('blacklight.bookmarks.clear.failure')
@@ -95,6 +77,6 @@ class BookmarksController < ApplicationController
95
77
 
96
78
  protected
97
79
  def verify_user
98
- flash[:notice] = I18n.t('blacklight.bookmarks.need_login') and raise Blacklight::Exceptions::AccessDenied unless current_user
80
+ flash[:notice] = I18n.t('blacklight.bookmarks.need_login') and raise Blacklight::Exceptions::AccessDenied unless current_or_guest_user
99
81
  end
100
82
  end
@@ -73,21 +73,19 @@ module Blacklight::BlacklightHelperBehavior
73
73
  end
74
74
 
75
75
  # Save function area for search results 'index' view, normally
76
- # renders next to title. Includes just 'Folder' by default.
76
+ # renders next to title.
77
77
  def render_index_doc_actions(document, options={})
78
78
  content = []
79
- content << render(:partial => 'catalog/bookmark_control', :locals => {:document=> document}.merge(options)) if has_user_authentication_provider? and current_user
80
- content << render(:partial => 'catalog/folder_control', :locals => {:document=> document}.merge(options))
79
+ content << render(:partial => 'catalog/bookmark_control', :locals => {:document=> document}.merge(options)) if has_user_authentication_provider? and current_or_guest_user
81
80
 
82
81
  content_tag("div", content.join("\n").html_safe, :class=>"documentFunctions")
83
82
  end
84
83
 
85
84
  # Save function area for item detail 'show' view, normally
86
- # renders next to title. By default includes 'Folder' and 'Bookmarks'
85
+ # renders next to title. By default includes 'Bookmarks'
87
86
  def render_show_doc_actions(document=@document, options={})
88
87
  content = []
89
- content << render(:partial => 'catalog/bookmark_control', :locals => {:document=> document}.merge(options)) if has_user_authentication_provider? and current_user
90
- content << render(:partial => 'catalog/folder_control', :locals => {:document=> document}.merge(options))
88
+ content << render(:partial => 'catalog/bookmark_control', :locals => {:document=> document}.merge(options)) if has_user_authentication_provider? and current_or_guest_user
91
89
 
92
90
  content_tag("div", content.join("\n").html_safe, :class=>"documentFunctions")
93
91
  end
@@ -344,11 +342,6 @@ module Blacklight::BlacklightHelperBehavior
344
342
  return result
345
343
  end
346
344
 
347
- # determines if the given document id is in the folder
348
- def item_in_folder?(doc_id)
349
- session[:folder_document_ids] && session[:folder_document_ids].include?(doc_id) ? true : false
350
- end
351
-
352
345
  # puts together a collection of documents into one refworks export string
353
346
  def render_refworks_texts(documents)
354
347
  val = ''
@@ -32,14 +32,15 @@ module Blacklight::FacetsHelperBehavior
32
32
  def facet_by_field_name solr_field
33
33
  case solr_field
34
34
  when String, Symbol
35
- @response.facet_by_field_name(solr_field)
35
+ extract_solr_facet_by_field_name(solr_field)
36
36
  when Blacklight::Configuration::FacetField
37
- @response.facet_by_field_name(solr_field.field)
37
+ extract_solr_facet_by_field_name(solr_field.field)
38
38
  else
39
39
  solr_field
40
40
  end
41
41
  end
42
42
 
43
+
43
44
  # used in the catalog/_facets partial and elsewhere
44
45
  # Renders a single section for facet limit with a specified
45
46
  # solr field used for faceting. Can be over-ridden for custom
@@ -95,7 +96,7 @@ module Blacklight::FacetsHelperBehavior
95
96
  # options consist of:
96
97
  # :suppress_link => true # do not make it a link, used for an already selected value for instance
97
98
  def render_facet_value(facet_solr_field, item, options ={})
98
- (link_to_unless(options[:suppress_link], item.value, add_facet_params_and_redirect(facet_solr_field, item.value), :class=>"facet_select label") + " " + render_facet_count(item.hits)).html_safe
99
+ (link_to_unless(options[:suppress_link], ((item.label if item.respond_to?(:label)) || item.value), add_facet_params_and_redirect(facet_solr_field, item.value), :class=>"facet_select label") + " " + render_facet_count(item.hits)).html_safe
99
100
  end
100
101
 
101
102
  # Standard display of a SELECTED facet value, no link, special span
@@ -117,9 +118,18 @@ module Blacklight::FacetsHelperBehavior
117
118
  # is suitable for a redirect. See
118
119
  # add_facet_params_and_redirect
119
120
  def add_facet_params(field, value)
121
+ facet_config = facet_configuration_for_field(field)
122
+
123
+
124
+
120
125
  p = params.dup
121
126
  p[:f] = (p[:f] || {}).dup # the command above is not deep in rails3, !@#$!@#$
122
127
  p[:f][field] = (p[:f][field] || []).dup
128
+
129
+ if facet_config.single and not p[:f][field].empty?
130
+ p[:f][field] = []
131
+ end
132
+
123
133
  p[:f][field].push(value)
124
134
  p
125
135
  end
@@ -172,5 +182,48 @@ module Blacklight::FacetsHelperBehavior
172
182
  def facet_in_params?(field, value)
173
183
  params[:f] and params[:f][field] and params[:f][field].include?(value)
174
184
  end
175
-
185
+
186
+ def facet_display_value field, value
187
+
188
+ facet_config = facet_configuration_for_field(field)
189
+
190
+ display_label = value
191
+
192
+ if facet_config.query and facet_config.query[value]
193
+ display_label = facet_config.query[value][:label]
194
+ end
195
+
196
+ if facet_config.date
197
+ localization_options = {}
198
+ localization_options = facet_config.date unless facet_config.date === true
199
+ display_label = l(value.to_datetime, localization_options)
200
+ end
201
+
202
+ display_label
203
+ end
204
+
205
+ private
206
+
207
+ # Get the solr response for the solr field :field
208
+ def extract_solr_facet_by_field_name facet_name
209
+ facet_field = facet_configuration_for_field(facet_name)
210
+ case
211
+ when facet_field.query
212
+ create_rsolr_facet_field_response_for_query_facet_field facet_name, facet_field
213
+ else
214
+ @response.facet_by_field_name(facet_name)
215
+ end
216
+ end
217
+
218
+ def create_rsolr_facet_field_response_for_query_facet_field facet_name, facet_field
219
+ salient_facet_queries = facet_field.query.map { |k, x| x[:fq] }
220
+ items = []
221
+ @response.facet_queries.select { |k,v| salient_facet_queries.include?(k) }.reject { |value, hits| hits == 0 }.map do |value,hits|
222
+ salient_fields = facet_field.query.select { |key, val| val[:fq] == value }
223
+ key = ((salient_fields.keys if salient_fields.respond_to? :keys) || salient_fields.first).first
224
+ items << OpenStruct.new(:value => key, :hits => hits, :label => facet_field.query[key][:label])
225
+ end
226
+
227
+ RSolr::Ext::Response::Facets::FacetField.new facet_name, items
228
+ end
176
229
  end
@@ -43,9 +43,12 @@ module Blacklight::RenderConstraintsHelperBehavior
43
43
  end
44
44
 
45
45
  def render_filter_element(facet, values, localized_params)
46
+ facet_config = facet_configuration_for_field(facet)
47
+
46
48
  values.map do |val|
49
+
47
50
  render_constraint_element( facet_field_labels[facet],
48
- val,
51
+ facet_display_value(facet, val),
49
52
  :remove => url_for(remove_facet_params(facet, val, localized_params)),
50
53
  :classes => ["filter", "filter-" + facet.parameterize]
51
54
  ) + "\n"
@@ -41,7 +41,7 @@ module Blacklight::SearchHistoryConstraintsHelperBehavior
41
41
  # 'and'. Pass in option :escape_value => false to pass in pre-rendered
42
42
  # html for value. key with escape_key if needed.
43
43
  def render_search_to_s_element(key, value, options = {})
44
- content_tag(:span, render_filter_name(key) + render_filter_value(value), :class => 'constraint')
44
+ content_tag(:span, render_filter_name(key) + render_filter_value(value, key), :class => 'constraint')
45
45
  end
46
46
 
47
47
  def render_filter_name name
@@ -49,8 +49,10 @@ module Blacklight::SearchHistoryConstraintsHelperBehavior
49
49
  content_tag(:span, t('blacklight.search.filters.label', :label => name), :class => 'filterName')
50
50
  end
51
51
 
52
- def render_filter_value value
53
- content_tag(:span, h(value), :class => 'filterValue')
52
+ def render_filter_value value, key = nil
53
+ display_value = value
54
+ display_value = facet_display_value(key, value) if key
55
+ content_tag(:span, h(display_value), :class => 'filterValue')
54
56
  end
55
57
 
56
58
  end
@@ -1,15 +1,16 @@
1
1
  <% if has_user_authentication_provider? %>
2
- <% if current_user%>
2
+ <% if current_user %>
3
3
  <%= link_to t('blacklight.header_links.logout'), destroy_user_session_path %> [<%= link_to current_user, edit_user_registration_path %>]
4
+ <% else %>
5
+ <%= link_to t('blacklight.header_links.login'), new_user_session_path %>
6
+ <% end %>
4
7
  |
8
+ <% end %>
5
9
  <%= link_to t('blacklight.header_links.bookmarks'), bookmarks_path %>
10
+ <% if current_user %>
6
11
  |
7
12
  <%= link_to t('blacklight.header_links.saved_searches'), saved_searches_path %>
8
- <% else %>
9
- <%= link_to t('blacklight.header_links.login'), new_user_session_path %>
10
13
  <% end %>
11
- |
12
- <% end %>
13
- <%= link_to t('blacklight.header_links.selected_items'), folder_index_path %> (<span id="folder_number"><%= "#{session[:folder_document_ids] ? session[:folder_document_ids].length : 0}" %></span>)
14
- |
14
+ |
15
15
  <%= link_to t('blacklight.header_links.search_history'), search_history_path %>
16
+
@@ -1,6 +1,6 @@
1
1
  <h1><%= t('blacklight.bookmarks.title') %></h1>
2
2
 
3
- <%- if current_user.blank? -%>
3
+ <%- if current_or_guest_user.blank? -%>
4
4
 
5
5
  <h2><%= t('blacklight.bookmarks.need_login') %></h2>
6
6
 
@@ -1,5 +1,5 @@
1
- <% if has_user_authentication_provider? and current_user %>
2
- <%- existing_bookmark = current_user.existing_bookmark_for(document.id) -%>
1
+ <% if has_user_authentication_provider? and current_or_guest_user %>
2
+ <%- existing_bookmark = current_or_guest_user.existing_bookmark_for(document.id) -%>
3
3
  <%-
4
4
  # Note these two forms are pretty similar but for different :methods, classes, and labels.
5
5
  # but it was simpler to leave them seperate instead of DRYing them, got confusing trying that.
@@ -15,7 +15,8 @@ module Blacklight
15
15
  :show => OpenStructWithHashAccess.new(:html_title => SolrDocument.unique_key, :heading => SolrDocument.unique_key),
16
16
  :index => OpenStructWithHashAccess.new(:show_link => SolrDocument.unique_key),
17
17
  :spell_max => 5,
18
- :max_per_page => 100
18
+ :max_per_page => 100,
19
+ :add_facet_fields_to_solr_request => false
19
20
  }
20
21
 
21
22
 
@@ -23,6 +24,7 @@ module Blacklight
23
24
  require 'blacklight/configuration/fields'
24
25
  require 'blacklight/configuration/solr_field'
25
26
  require 'blacklight/configuration/search_field'
27
+ require 'blacklight/configuration/facet_field'
26
28
  require 'blacklight/configuration/sort_field'
27
29
  include Fields
28
30
 
@@ -68,6 +70,17 @@ module Blacklight
68
70
  field
69
71
  end
70
72
 
73
+ # Add any configured facet fields to the default solr parameters hash
74
+ def add_facet_fields_to_solr_request!
75
+ self.add_facet_fields_to_solr_request = true
76
+ end
77
+
78
+ def facet_fields_to_add_to_solr
79
+ return facet_fields.reject { |k,v| v[:query] }.map { |k,v| v.field } if self.add_facet_fields_to_solr_request
80
+
81
+ []
82
+ end
83
+
71
84
  ##
72
85
  # Provide a 'deep copy' of Blacklight::Configuration that can be modifyed without affecting
73
86
  # the original Blacklight::Configuration instance.
@@ -0,0 +1,14 @@
1
+ module Blacklight
2
+ class Configuration::FacetField < Blacklight::Configuration::SolrField
3
+ def normalize! blacklight_config
4
+ self.query.stringify_keys! if self.query
5
+
6
+ if self.single and self.tag.blank? and self.ex.blank?
7
+ self.tag = "#{self.field}_single"
8
+ self.ex = "#{self.field}_single"
9
+ end
10
+ super
11
+ end
12
+ end
13
+ end
14
+
@@ -25,6 +25,22 @@ module Blacklight::Controller
25
25
  base.send :helper_method, :stylesheet_links
26
26
  base.send :helper_method, :javascript_includes
27
27
  base.send :helper_method, :has_user_authentication_provider?
28
+
29
+
30
+ # This callback runs when a user first logs in
31
+ base.set_callback :logging_in_user, :before, :transfer_guest_user_actions_to_current_user rescue nil
32
+
33
+ end
34
+
35
+ def method_missing(meth, *args, &block)
36
+ if meth.to_s == "current_or_guest_user"
37
+ # Add the method
38
+ define_method(meth) { blacklight_current_or_guest_user }
39
+
40
+ blacklight_current_or_guest_user
41
+ else
42
+ super
43
+ end
28
44
  end
29
45
 
30
46
  # test for exception notifier plugin
@@ -96,15 +112,17 @@ module Blacklight::Controller
96
112
  'blacklight'
97
113
  end
98
114
 
99
- def current_user_session
100
- puts "DEPRICATED: Please use Devise, Authlogic or other authentication system."
101
- user_session # method provided by devise
102
- end
103
-
104
- # Should be provided by devise
115
+ # Should be provided by authentication provider
105
116
  # def current_user
106
117
  # end
107
-
118
+ # def current_or_guest_user
119
+ # end
120
+
121
+ # Here's a stub implementation we'll add if it isn't provided for us
122
+ def blacklight_current_or_guest_user
123
+ current_user if has_user_authentication_provider?
124
+ end
125
+
108
126
  ##
109
127
  # We discard flash messages generated by the xhr requests to avoid
110
128
  # confusing UX.
@@ -122,6 +140,25 @@ module Blacklight::Controller
122
140
  def require_user_authentication_provider
123
141
  raise ActionController::RoutingError.new('Not Found') unless has_user_authentication_provider?
124
142
  end
143
+
144
+ ##
145
+ # When a user logs in, transfer any saved searches or bookmarks to the current_user
146
+ def transfer_guest_user_actions_to_current_user
147
+ return unless respond_to? :current_user and respond_to? :guest_user and current_user and guest_user
148
+ current_user_searches = current_user.searches.all.collect(&:query_params)
149
+ current_user_bookmarks = current_user.bookmarks.all.collect(&:document_id)
150
+
151
+ guest_user.searches.all.reject { |s| current_user_searches.include?(s.query_params)}.each do |s|
152
+ s.user_id = current_user.id
153
+ s.save
154
+ end
155
+
156
+ guest_user.bookmarks.all.reject { |b| current_user_bookmarks.include?(b.document_id)}.each do |b|
157
+ b.user_id = current_user.id
158
+ b.save
159
+ end
160
+ end
161
+
125
162
  ##
126
163
  # To handle failed authorization attempts, redirect the user to the
127
164
  # login form and persist the current request uri as a parameter