blacklight 3.6.1.1 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
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