diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index eb58983..9826b92 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -154,20 +154,21 @@ class ApplicationController < ActionController::Base end end - def find_by_contents(scope, query, paginate_options={:page => 1}, options={}) + def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) scope = scope.send(options[:filter]) if options[:filter] - return {:results => scope.paginate(paginate_options)} if query.blank? - @plugins.first(:find_by_contents, scope, query, paginate_options, options) || - fallback_find_by_contents(scope, query, paginate_options, options) + @plugins.first(:find_by_contents, asset, scope, query, paginate_options, options) || + fallback_find_by_contents(asset, scope, query, paginate_options, options) end private - def fallback_find_by_contents(scope, query, paginate_options, options) - fields = scope.base_class::SEARCHABLE_FIELDS.keys.map(&:to_s) & scope.base_class.column_names + def fallback_find_by_contents(asset, scope, query, paginate_options, options) + return {:results => scope.paginate(paginate_options)} if query.blank? + klass = asset.to_s.singularize.camelize.constantize + fields = klass::SEARCHABLE_FIELDS.keys.map(&:to_s) & klass.column_names conditions = fields.map do |field| - "lower(#{scope.base_class.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" + "lower(#{klass.table_name}.#{field}) LIKE \"%#{query.downcase.strip}%\"" end.join(' OR ') {:results => scope.where(conditions).paginate(paginate_options)} end diff --git a/app/controllers/public/search_controller.rb b/app/controllers/public/search_controller.rb index 119909c..5b856bd 100644 --- a/app/controllers/public/search_controller.rb +++ b/app/controllers/public/search_controller.rb @@ -211,7 +211,7 @@ class SearchController < PublicController end def full_text_search - @searches[@asset] = find_by_contents(@scope, @query, paginate_options, {:category => @category, :filter => @filter}) + @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter}) end private diff --git a/lib/noosfero/plugin.rb b/lib/noosfero/plugin.rb index f04acfe..d3bb6ef 100644 --- a/lib/noosfero/plugin.rb +++ b/lib/noosfero/plugin.rb @@ -355,7 +355,7 @@ class Noosfero::Plugin # returns = {:results => [a, b, c, ...], ...} # P.S.: The plugin might add other informations on the return hash for its # own use in specific views - def find_by_contents(klass, query, paginate_options={}, options={}) + def find_by_contents(asset, klass, query, paginate_options={}, options={}) end def method_missing(method, *args, &block) diff --git a/plugins/solr/lib/solr_plugin.rb b/plugins/solr/lib/solr_plugin.rb index 904ce2a..a83ad30 100644 --- a/plugins/solr/lib/solr_plugin.rb +++ b/plugins/solr/lib/solr_plugin.rb @@ -20,11 +20,15 @@ class SolrPlugin < Noosfero::Plugin true end - def find_by_contents(klass, query, paginate_options={}, options={}) + def find_by_contents(asset, scope, query, paginate_options={}, options={}) + klass = asset_class(asset) category = options.delete(:category) filter = options.delete(:filter) + + return if empty_query?(query, category) && klass != Product + solr_options = solr_options(class_asset(klass), category) - user = context.respond_to?(:user) ? context.send(:user) : nil + user = context.send(:logged_in?) ? context.send(:user) : nil solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) klass.find_by_contents(query, paginate_options, solr_options.merge(options)) end diff --git a/plugins/solr/lib/solr_plugin/search_helper.rb b/plugins/solr/lib/solr_plugin/search_helper.rb index 3d7626a..41e92d0 100644 --- a/plugins/solr/lib/solr_plugin/search_helper.rb +++ b/plugins/solr/lib/solr_plugin/search_helper.rb @@ -45,15 +45,11 @@ module SolrPlugin::SearchHelper def asset_table(asset) asset_class(asset).table_name end -# -# def multiple_search? -# ['index', 'category_index'].include?(context.params[:action]) -# end def filters(asset) case asset when :products - ['solr_plugin_public:true'] + ['solr_plugin_public:true', 'enabled:true'] when :events [] else @@ -69,6 +65,24 @@ module SolrPlugin::SearchHelper category.nil? && query.blank? end + def products_options(person) + geosearch = person && person.lat && person.lng + + extra_limit = LIST_SEARCH_LIMIT*5 + sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} + options = {:sql_options => sql_options, :extra_limit => extra_limit} + + if geosearch + options.merge({ + :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", + :radius => DistFilt, + :latitude => person.lat, + :longitude => person.lng }) + else + options.merge({:boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']}) + end + end + def solr_options(asset, category) asset_class = asset_class(asset) solr_options = {} @@ -95,21 +109,6 @@ module SolrPlugin::SearchHelper solr_options end - def products_options(person) - geosearch = person && person.lat && person.lng - - extra_limit = LIST_SEARCH_LIMIT*5 - sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} - if geosearch - {:sql_options => sql_options, :extra_limit => extra_limit, - :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", - :radius => DistFilt, :latitude => person.lat, :longitude => person.lng} - else - { :sql_options => sql_options, :extra_limit => extra_limit, - :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']} - end - end - def asset_class(asset) asset.to_s.singularize.camelize.constantize end diff --git a/plugins/solr/test/functional/search_controller_test.rb b/plugins/solr/test/functional/search_controller_test.rb index 790fab7..ac76369 100644 --- a/plugins/solr/test/functional/search_controller_test.rb +++ b/plugins/solr/test/functional/search_controller_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -require 'test_solr_helper' +require File.dirname(__FILE__) + '/../test_solr_helper' require File.dirname(__FILE__) + '/../../lib/ext/facets_browse' # Re-raise errors caught by the controller. @@ -108,7 +108,7 @@ class SearchControllerTest < ActionController::TestCase prod2 = ent2.products.create!(:name => 'another beautiful product', :product_category => @product_category) get :products - assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results] + assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results].docs assert_match 'Highlights', @response.body end @@ -156,45 +156,45 @@ class SearchControllerTest < ActionController::TestCase end # Testing random sequences always have a small chance of failing -# should 'randomize product display in empty search' do -# prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) -# ent = create_profile_with_optional_category(Enterprise, 'test enterprise') -# (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| -# fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) -# end -# -# get :products -# result1 = assigns(:searches)[:products][:results].map(&:id) -# -# (1..10).each do |n| -# get :products -# end -# result2 = assigns(:searches)[:products][:results].map(&:id) -# -# assert_not_equal result1, result2 -# end -# -# should 'remove far products by geolocalization empty logged search' do -# user = create_user('a_logged_user') -# # trigger geosearch -# user.person.lat = '1.0' -# user.person.lng = '1.0' -# SearchController.any_instance.stubs(:logged_in?).returns(true) -# SearchController.any_instance.stubs(:current_user).returns(user) -# -# cat = fast_create(ProductCategory) -# ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') -# prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) -# ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') -# prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) -# ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') -# prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) -# ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') -# prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) -# -# get :products -# assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results] -# end + should 'randomize product display in empty search' do + prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default) + ent = create_profile_with_optional_category(Enterprise, 'test enterprise') + (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n| + fast_create(Product, {:name => "produto #{n}", :enterprise_id => ent.id, :product_category_id => prod_cat.id}, :search => true) + end + + get :products + result1 = assigns(:searches)[:products][:results].map(&:id) + + (1..10).each do |n| + get :products + end + result2 = assigns(:searches)[:products][:results].map(&:id) + + assert_not_equal result1, result2 + end + + should 'remove far products by geolocalization empty logged search' do + user = create_user('a_logged_user') + # trigger geosearch + user.person.lat = '1.0' + user.person.lng = '1.0' + SearchController.any_instance.stubs(:logged_in?).returns(true) + SearchController.any_instance.stubs(:current_user).returns(user) + + cat = fast_create(ProductCategory) + ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3') + prod1 = Product.create!(:name => 'produto 1', :enterprise_id => ent1.id, :product_category_id => cat.id) + ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0') + prod2 = Product.create!(:name => 'produto 2', :enterprise_id => ent2.id, :product_category_id => cat.id) + ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6') + prod3 = Product.create!(:name => 'produto 3', :enterprise_id => ent3.id, :product_category_id => cat.id) + ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10') + prod4 = Product.create!(:name => 'produto 4', :enterprise_id => ent4.id, :product_category_id => cat.id) + + get :products + assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results].docs + end should 'browse facets when query is not empty' do get :articles, :query => 'something' diff --git a/plugins/solr/test/test_solr_helper.rb b/plugins/solr/test/test_solr_helper.rb new file mode 100644 index 0000000..e5535b9 --- /dev/null +++ b/plugins/solr/test/test_solr_helper.rb @@ -0,0 +1,59 @@ +class ActsAsSolr::Post + class << self + alias_method :execute_orig, :execute + end +end +module ActsAsSolr::ParserMethods + alias_method :parse_results_orig, :parse_results +end + +class TestSolr + + def self.enable + ActsAsSolr::Post.class_eval do + def self.execute(*args) + execute_orig *args + end + end + ActsAsSolr::ParserMethods.module_eval do + def parse_results(*args) + parse_results_orig *args + end + end + + # clear index + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) + + @solr_disabled = false + end + + def self.disable + return if @solr_disabled + + ActsAsSolr::Post.class_eval do + def self.execute(*args) + true + end + end + ActsAsSolr::ParserMethods.module_eval do + def parse_results(*args) + parse_results_orig nil, args[1] + end + end + + @solr_disabled = true + end + +end + +class ActiveSupport::TestCase + def fast_create_with_solr(name, attrs = {}, options = {}) + obj = fast_create_without_solr(name, attrs, options) + obj.solr_save if options[:search] + obj + end + alias_method_chain :fast_create, :solr +end + +# disable solr actions by default +TestSolr.disable diff --git a/test/test_solr_helper.rb b/test/test_solr_helper.rb deleted file mode 100644 index 9e77e27..0000000 --- a/test/test_solr_helper.rb +++ /dev/null @@ -1,50 +0,0 @@ -class ActsAsSolr::Post - class << self - alias_method :execute_orig, :execute - end -end -module ActsAsSolr::ParserMethods - alias_method :parse_results_orig, :parse_results -end - -class TestSolr - - def self.enable - ActsAsSolr::Post.class_eval do - def self.execute(*args) - execute_orig *args - end - end - ActsAsSolr::ParserMethods.module_eval do - def parse_results(*args) - parse_results_orig *args - end - end - - # clear index - ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) - - @solr_disabled = false - end - - def self.disable - return if @solr_disabled - - ActsAsSolr::Post.class_eval do - def self.execute(*args) - true - end - end - ActsAsSolr::ParserMethods.module_eval do - def parse_results(*args) - parse_results_orig nil, args[1] - end - end - - @solr_disabled = true - end - -end - -# disable solr actions by default -TestSolr.disable -- libgit2 0.21.2