Commit d2e3b9ec048d4f8eaac95b5efc041458b894261e
1 parent
5cac53de
Exists in
master
and in
29 other branches
Search controller plugin test done
Showing
8 changed files
with
135 additions
and
122 deletions
Show diff stats
app/controllers/application_controller.rb
@@ -154,20 +154,21 @@ class ApplicationController < ActionController::Base | @@ -154,20 +154,21 @@ class ApplicationController < ActionController::Base | ||
154 | end | 154 | end |
155 | end | 155 | end |
156 | 156 | ||
157 | - def find_by_contents(scope, query, paginate_options={:page => 1}, options={}) | 157 | + def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) |
158 | scope = scope.send(options[:filter]) if options[:filter] | 158 | scope = scope.send(options[:filter]) if options[:filter] |
159 | - return {:results => scope.paginate(paginate_options)} if query.blank? | ||
160 | 159 | ||
161 | - @plugins.first(:find_by_contents, scope, query, paginate_options, options) || | ||
162 | - fallback_find_by_contents(scope, query, paginate_options, options) | 160 | + @plugins.first(:find_by_contents, asset, scope, query, paginate_options, options) || |
161 | + fallback_find_by_contents(asset, scope, query, paginate_options, options) | ||
163 | end | 162 | end |
164 | 163 | ||
165 | private | 164 | private |
166 | 165 | ||
167 | - def fallback_find_by_contents(scope, query, paginate_options, options) | ||
168 | - fields = scope.base_class::SEARCHABLE_FIELDS.keys.map(&:to_s) & scope.base_class.column_names | 166 | + def fallback_find_by_contents(asset, scope, query, paginate_options, options) |
167 | + return {:results => scope.paginate(paginate_options)} if query.blank? | ||
168 | + klass = asset.to_s.singularize.camelize.constantize | ||
169 | + fields = klass::SEARCHABLE_FIELDS.keys.map(&:to_s) & klass.column_names | ||
169 | conditions = fields.map do |field| | 170 | conditions = fields.map do |field| |
170 | - "lower(#{scope.base_class.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" | 171 | + "lower(#{klass.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" |
171 | end.join(' OR ') | 172 | end.join(' OR ') |
172 | {:results => scope.where(conditions).paginate(paginate_options)} | 173 | {:results => scope.where(conditions).paginate(paginate_options)} |
173 | end | 174 | end |
app/controllers/public/search_controller.rb
@@ -211,7 +211,7 @@ class SearchController < PublicController | @@ -211,7 +211,7 @@ class SearchController < PublicController | ||
211 | end | 211 | end |
212 | 212 | ||
213 | def full_text_search | 213 | def full_text_search |
214 | - @searches[@asset] = find_by_contents(@scope, @query, paginate_options, {:category => @category, :filter => @filter}) | 214 | + @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter}) |
215 | end | 215 | end |
216 | 216 | ||
217 | private | 217 | private |
lib/noosfero/plugin.rb
@@ -355,7 +355,7 @@ class Noosfero::Plugin | @@ -355,7 +355,7 @@ class Noosfero::Plugin | ||
355 | # returns = {:results => [a, b, c, ...], ...} | 355 | # returns = {:results => [a, b, c, ...], ...} |
356 | # P.S.: The plugin might add other informations on the return hash for its | 356 | # P.S.: The plugin might add other informations on the return hash for its |
357 | # own use in specific views | 357 | # own use in specific views |
358 | - def find_by_contents(klass, query, paginate_options={}, options={}) | 358 | + def find_by_contents(asset, klass, query, paginate_options={}, options={}) |
359 | end | 359 | end |
360 | 360 | ||
361 | def method_missing(method, *args, &block) | 361 | def method_missing(method, *args, &block) |
plugins/solr/lib/solr_plugin.rb
@@ -20,11 +20,15 @@ class SolrPlugin < Noosfero::Plugin | @@ -20,11 +20,15 @@ class SolrPlugin < Noosfero::Plugin | ||
20 | true | 20 | true |
21 | end | 21 | end |
22 | 22 | ||
23 | - def find_by_contents(klass, query, paginate_options={}, options={}) | 23 | + def find_by_contents(asset, scope, query, paginate_options={}, options={}) |
24 | + klass = asset_class(asset) | ||
24 | category = options.delete(:category) | 25 | category = options.delete(:category) |
25 | filter = options.delete(:filter) | 26 | filter = options.delete(:filter) |
27 | + | ||
28 | + return if empty_query?(query, category) && klass != Product | ||
29 | + | ||
26 | solr_options = solr_options(class_asset(klass), category) | 30 | solr_options = solr_options(class_asset(klass), category) |
27 | - user = context.respond_to?(:user) ? context.send(:user) : nil | 31 | + user = context.send(:logged_in?) ? context.send(:user) : nil |
28 | solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) | 32 | solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) |
29 | klass.find_by_contents(query, paginate_options, solr_options.merge(options)) | 33 | klass.find_by_contents(query, paginate_options, solr_options.merge(options)) |
30 | end | 34 | end |
plugins/solr/lib/solr_plugin/search_helper.rb
@@ -45,15 +45,11 @@ module SolrPlugin::SearchHelper | @@ -45,15 +45,11 @@ module SolrPlugin::SearchHelper | ||
45 | def asset_table(asset) | 45 | def asset_table(asset) |
46 | asset_class(asset).table_name | 46 | asset_class(asset).table_name |
47 | end | 47 | end |
48 | -# | ||
49 | -# def multiple_search? | ||
50 | -# ['index', 'category_index'].include?(context.params[:action]) | ||
51 | -# end | ||
52 | 48 | ||
53 | def filters(asset) | 49 | def filters(asset) |
54 | case asset | 50 | case asset |
55 | when :products | 51 | when :products |
56 | - ['solr_plugin_public:true'] | 52 | + ['solr_plugin_public:true', 'enabled:true'] |
57 | when :events | 53 | when :events |
58 | [] | 54 | [] |
59 | else | 55 | else |
@@ -69,6 +65,24 @@ module SolrPlugin::SearchHelper | @@ -69,6 +65,24 @@ module SolrPlugin::SearchHelper | ||
69 | category.nil? && query.blank? | 65 | category.nil? && query.blank? |
70 | end | 66 | end |
71 | 67 | ||
68 | + def products_options(person) | ||
69 | + geosearch = person && person.lat && person.lng | ||
70 | + | ||
71 | + extra_limit = LIST_SEARCH_LIMIT*5 | ||
72 | + sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | ||
73 | + options = {:sql_options => sql_options, :extra_limit => extra_limit} | ||
74 | + | ||
75 | + if geosearch | ||
76 | + options.merge({ | ||
77 | + :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", | ||
78 | + :radius => DistFilt, | ||
79 | + :latitude => person.lat, | ||
80 | + :longitude => person.lng }) | ||
81 | + else | ||
82 | + options.merge({:boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']}) | ||
83 | + end | ||
84 | + end | ||
85 | + | ||
72 | def solr_options(asset, category) | 86 | def solr_options(asset, category) |
73 | asset_class = asset_class(asset) | 87 | asset_class = asset_class(asset) |
74 | solr_options = {} | 88 | solr_options = {} |
@@ -95,21 +109,6 @@ module SolrPlugin::SearchHelper | @@ -95,21 +109,6 @@ module SolrPlugin::SearchHelper | ||
95 | solr_options | 109 | solr_options |
96 | end | 110 | end |
97 | 111 | ||
98 | - def products_options(person) | ||
99 | - geosearch = person && person.lat && person.lng | ||
100 | - | ||
101 | - extra_limit = LIST_SEARCH_LIMIT*5 | ||
102 | - sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} | ||
103 | - if geosearch | ||
104 | - {:sql_options => sql_options, :extra_limit => extra_limit, | ||
105 | - :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", | ||
106 | - :radius => DistFilt, :latitude => person.lat, :longitude => person.lng} | ||
107 | - else | ||
108 | - { :sql_options => sql_options, :extra_limit => extra_limit, | ||
109 | - :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']} | ||
110 | - end | ||
111 | - end | ||
112 | - | ||
113 | def asset_class(asset) | 112 | def asset_class(asset) |
114 | asset.to_s.singularize.camelize.constantize | 113 | asset.to_s.singularize.camelize.constantize |
115 | end | 114 | end |
plugins/solr/test/functional/search_controller_test.rb
1 | require 'test_helper' | 1 | require 'test_helper' |
2 | -require 'test_solr_helper' | 2 | +require File.dirname(__FILE__) + '/../test_solr_helper' |
3 | require File.dirname(__FILE__) + '/../../lib/ext/facets_browse' | 3 | require File.dirname(__FILE__) + '/../../lib/ext/facets_browse' |
4 | 4 | ||
5 | # Re-raise errors caught by the controller. | 5 | # Re-raise errors caught by the controller. |
@@ -108,7 +108,7 @@ class SearchControllerTest < ActionController::TestCase | @@ -108,7 +108,7 @@ class SearchControllerTest < ActionController::TestCase | ||
108 | prod2 = ent2.products.create!(:name => 'another beautiful product', :product_category => @product_category) | 108 | prod2 = ent2.products.create!(:name => 'another beautiful product', :product_category => @product_category) |
109 | 109 | ||
110 | get :products | 110 | get :products |
111 | - assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results] | 111 | + assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results].docs |
112 | assert_match 'Highlights', @response.body | 112 | assert_match 'Highlights', @response.body |
113 | end | 113 | end |
114 | 114 | ||
@@ -156,45 +156,45 @@ class SearchControllerTest < ActionController::TestCase | @@ -156,45 +156,45 @@ class SearchControllerTest < ActionController::TestCase | ||
156 | end | 156 | end |
157 | 157 | ||
158 | # Testing random sequences always have a small chance of failing | 158 | # Testing random sequences always have a small chance of failing |
159 | -# should 'randomize product display in empty search' do | ||
160 | -# prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) | ||
161 | -# ent = create_profile_with_optional_category(Enterprise, 'test enterprise') | ||
162 | -# (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| | ||
163 | -# fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) | ||
164 | -# end | ||
165 | -# | ||
166 | -# get :products | ||
167 | -# result1 = assigns(:searches)[:products][:results].map(&:id) | ||
168 | -# | ||
169 | -# (1..10).each do |n| | ||
170 | -# get :products | ||
171 | -# end | ||
172 | -# result2 = assigns(:searches)[:products][:results].map(&:id) | ||
173 | -# | ||
174 | -# assert_not_equal result1, result2 | ||
175 | -# end | ||
176 | -# | ||
177 | -# should 'remove far products by geolocalization empty logged search' do | ||
178 | -# user = create_user('a_logged_user') | ||
179 | -# # trigger geosearch | ||
180 | -# user.person.lat = '1.0' | ||
181 | -# user.person.lng = '1.0' | ||
182 | -# SearchController.any_instance.stubs(:logged_in?).returns(true) | ||
183 | -# SearchController.any_instance.stubs(:current_user).returns(user) | ||
184 | -# | ||
185 | -# cat = fast_create(ProductCategory) | ||
186 | -# ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') | ||
187 | -# prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) | ||
188 | -# ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') | ||
189 | -# prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) | ||
190 | -# ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') | ||
191 | -# prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) | ||
192 | -# ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') | ||
193 | -# prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) | ||
194 | -# | ||
195 | -# get :products | ||
196 | -# assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results] | ||
197 | -# end | 159 | + should 'randomize product display in empty search' do |
160 | + prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) | ||
161 | + ent = create_profile_with_optional_category(Enterprise, 'test enterprise') | ||
162 | + (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| | ||
163 | + fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) | ||
164 | + end | ||
165 | + | ||
166 | + get :products | ||
167 | + result1 = assigns(:searches)[:products][:results].map(&:id) | ||
168 | + | ||
169 | + (1..10).each do |n| | ||
170 | + get :products | ||
171 | + end | ||
172 | + result2 = assigns(:searches)[:products][:results].map(&:id) | ||
173 | + | ||
174 | + assert_not_equal result1, result2 | ||
175 | + end | ||
176 | + | ||
177 | + should 'remove far products by geolocalization empty logged search' do | ||
178 | + user = create_user('a_logged_user') | ||
179 | + # trigger geosearch | ||
180 | + user.person.lat = '1.0' | ||
181 | + user.person.lng = '1.0' | ||
182 | + SearchController.any_instance.stubs(:logged_in?).returns(true) | ||
183 | + SearchController.any_instance.stubs(:current_user).returns(user) | ||
184 | + | ||
185 | + cat = fast_create(ProductCategory) | ||
186 | + ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') | ||
187 | + prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) | ||
188 | + ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') | ||
189 | + prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) | ||
190 | + ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') | ||
191 | + prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) | ||
192 | + ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') | ||
193 | + prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) | ||
194 | + | ||
195 | + get :products | ||
196 | + assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results].docs | ||
197 | + end | ||
198 | 198 | ||
199 | should 'browse facets when query is not empty' do | 199 | should 'browse facets when query is not empty' do |
200 | get :articles, :query => 'something' | 200 | get :articles, :query => 'something' |
@@ -0,0 +1,59 @@ | @@ -0,0 +1,59 @@ | ||
1 | +class ActsAsSolr::Post | ||
2 | + class << self | ||
3 | + alias_method :execute_orig, :execute | ||
4 | + end | ||
5 | +end | ||
6 | +module ActsAsSolr::ParserMethods | ||
7 | + alias_method :parse_results_orig, :parse_results | ||
8 | +end | ||
9 | + | ||
10 | +class TestSolr | ||
11 | + | ||
12 | + def self.enable | ||
13 | + ActsAsSolr::Post.class_eval do | ||
14 | + def self.execute(*args) | ||
15 | + execute_orig *args | ||
16 | + end | ||
17 | + end | ||
18 | + ActsAsSolr::ParserMethods.module_eval do | ||
19 | + def parse_results(*args) | ||
20 | + parse_results_orig *args | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + # clear index | ||
25 | + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) | ||
26 | + | ||
27 | + @solr_disabled = false | ||
28 | + end | ||
29 | + | ||
30 | + def self.disable | ||
31 | + return if @solr_disabled | ||
32 | + | ||
33 | + ActsAsSolr::Post.class_eval do | ||
34 | + def self.execute(*args) | ||
35 | + true | ||
36 | + end | ||
37 | + end | ||
38 | + ActsAsSolr::ParserMethods.module_eval do | ||
39 | + def parse_results(*args) | ||
40 | + parse_results_orig nil, args[1] | ||
41 | + end | ||
42 | + end | ||
43 | + | ||
44 | + @solr_disabled = true | ||
45 | + end | ||
46 | + | ||
47 | +end | ||
48 | + | ||
49 | +class ActiveSupport::TestCase | ||
50 | + def fast_create_with_solr(name, attrs = {}, options = {}) | ||
51 | + obj = fast_create_without_solr(name, attrs, options) | ||
52 | + obj.solr_save if options[:search] | ||
53 | + obj | ||
54 | + end | ||
55 | + alias_method_chain :fast_create, :solr | ||
56 | +end | ||
57 | + | ||
58 | +# disable solr actions by default | ||
59 | +TestSolr.disable |
test/test_solr_helper.rb
@@ -1,50 +0,0 @@ | @@ -1,50 +0,0 @@ | ||
1 | -class ActsAsSolr::Post | ||
2 | - class << self | ||
3 | - alias_method :execute_orig, :execute | ||
4 | - end | ||
5 | -end | ||
6 | -module ActsAsSolr::ParserMethods | ||
7 | - alias_method :parse_results_orig, :parse_results | ||
8 | -end | ||
9 | - | ||
10 | -class TestSolr | ||
11 | - | ||
12 | - def self.enable | ||
13 | - ActsAsSolr::Post.class_eval do | ||
14 | - def self.execute(*args) | ||
15 | - execute_orig *args | ||
16 | - end | ||
17 | - end | ||
18 | - ActsAsSolr::ParserMethods.module_eval do | ||
19 | - def parse_results(*args) | ||
20 | - parse_results_orig *args | ||
21 | - end | ||
22 | - end | ||
23 | - | ||
24 | - # clear index | ||
25 | - ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) | ||
26 | - | ||
27 | - @solr_disabled = false | ||
28 | - end | ||
29 | - | ||
30 | - def self.disable | ||
31 | - return if @solr_disabled | ||
32 | - | ||
33 | - ActsAsSolr::Post.class_eval do | ||
34 | - def self.execute(*args) | ||
35 | - true | ||
36 | - end | ||
37 | - end | ||
38 | - ActsAsSolr::ParserMethods.module_eval do | ||
39 | - def parse_results(*args) | ||
40 | - parse_results_orig nil, args[1] | ||
41 | - end | ||
42 | - end | ||
43 | - | ||
44 | - @solr_disabled = true | ||
45 | - end | ||
46 | - | ||
47 | -end | ||
48 | - | ||
49 | -# disable solr actions by default | ||
50 | -TestSolr.disable |