From b660ef0e0481bf320eabac67a0c403e61b5246a2 Mon Sep 17 00:00:00 2001 From: MoisesMachado Date: Sat, 7 Jun 2008 17:45:10 +0000 Subject: [PATCH] ActionItem129: put the sidebar to the search of products that have been searched --- app/controllers/public/search_controller.rb | 22 +++++++++++++++++++--- app/models/article.rb | 2 +- app/models/category_finder.rb | 41 ++++++++++++++++++++++------------------- app/models/enterprise.rb | 2 +- app/models/environment_finder.rb | 18 ++++++++++++++---- app/models/product.rb | 2 +- app/models/profile.rb | 2 +- script/extract_sies_data.rb | 25 +++++++++++++++++-------- script/fbes_populate_helper.rb | 5 +++++ test/functional/search_controller_test.rb | 82 ++++++++++++++++++++++++++++++++++++++++++---------------------------------------- test/unit/category_finder_test.rb | 36 ++++++++++++++++++++++++++++++++++++ test/unit/environment_finder_test.rb | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/unit/product_test.rb | 4 ++-- 13 files changed, 221 insertions(+), 80 deletions(-) diff --git a/app/controllers/public/search_controller.rb b/app/controllers/public/search_controller.rb index 182c2e0..f8f68ff 100644 --- a/app/controllers/public/search_controller.rb +++ b/app/controllers/public/search_controller.rb @@ -108,6 +108,7 @@ class SearchController < ApplicationController def index @query = params[:query] || '' @filtered_query = remove_stop_words(@query) + @product_category = ProductCategory.find(params[:product_category]) if params[:product_category] # FIXME name is not unique @region = Region.find_by_name(params[:region][:name]) if params[:region] @@ -116,9 +117,9 @@ class SearchController < ApplicationController @names = {} SEARCH_IN.each do |key, description| if [:enterprises, :people].include?(key) && @region - @results[key] = @finder.find(key, @filtered_query, :within => params[:radius], :region => @region.id) if @searching[key] + @results[key] = @finder.find(key, @filtered_query, :within => params[:radius], :region => @region.id, :product_category => @product_category) if @searching[key] else - @results[key] = @finder.find(key, @filtered_query) if @searching[key] + @results[key] = @finder.find(key, @filtered_query, :product_category => @product_category) if @searching[key] end @names[key] = gettext(description) end @@ -136,6 +137,22 @@ class SearchController < ApplicationController render :action => 'index' end + def products + @categories = @results[:products].map(&:product_category).compact + @counts = @categories.uniq.inject({}) do |h, cat| + h[cat.id] = [cat, 0] + h + end + + @categories.each do |cat| + cat.hierarchy.each do |each_cat| + @counts[each_cat.id][1] += 1 if @counts[each_cat.id] + end + end + + @cats = @counts.values.sort_by{|v|v[0].full_name} + end + alias :assets :index ####################################################### @@ -148,7 +165,6 @@ class SearchController < ApplicationController [ :people, _('Recently registered people'), @finder.recent('people') ], [ :communities, _('Recently created communities'), @finder.recent('communities') ], [ :articles, _('Recent articles'), @finder.recent('articles') ], - [ :comments, _('Recent comments'), @finder.recent('comments') ], [ :most_commented_articles, _('Most commented articles'), @finder.most_commented_articles ], [ :enterprises, _('Recently created enterprises'), @finder.recent('enterprises') ], [ :events, _('Recently added events'), @finder.current_events(params[:year], params[:month]) ] diff --git a/app/models/article.rb b/app/models/article.rb index 4f5a04f..b4d1bef 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -26,7 +26,7 @@ class Article < ActiveRecord::Base def comment_data comments.map {|item| [item.title, item.body].join(' ') }.join(' ') end - + before_update do |article| article.advertise = true end diff --git a/app/models/category_finder.rb b/app/models/category_finder.rb index 3b6b540..8b6943a 100644 --- a/app/models/category_finder.rb +++ b/app/models/category_finder.rb @@ -7,11 +7,20 @@ class CategoryFinder attr_reader :category_ids + + def find(asset, query = nil, options={}, limit = nil) - if query.blank? - asset_class(asset).find(:all, options_for_find(asset_class(asset), {:limit => limit, :order => "created_at desc, #{asset_table(asset)}.id desc"})) + @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) + if @region && options[:within] + options[:origin] = [@region.lat, @region.lng] else - find_in_categorized(asset.to_s.singularize.camelize.constantize, query, options) + options.delete(:within) + end + + if query.blank? + asset_class(asset).find(:all, options_for_find(asset_class(asset), {:limit => limit, :order => "created_at desc, #{asset_table(asset)}.id desc"}.merge(options))) + else + asset_class(asset).find_by_contents(query, {}, options_for_find(asset_class(asset), options)).uniq end end @@ -39,27 +48,21 @@ class CategoryFinder protected - def find_in_categorized(klass, query, options={}) - @region = Region.find_by_id(options.delete(:region)) if options.has_key?(:region) - if @region && options[:within] - options[:origin] = [@region.lat, @region.lng] - else - options.delete(:within) - end - - if query.nil? - klass.find(:all, options_for_find(klass, options)) - else - klass.find_by_contents(query, {}, options_for_find(klass, options)).uniq - end - end - def options_for_find(klass, options={}) + if defined? options[:product_category] + prod_cat = options.delete(:product_category) + prod_cat_ids = prod_cat.map_traversal(&:id) if prod_cat + end + case klass.name when 'Comment' {:select => 'distinct comments.*', :joins => 'inner join articles_categories on articles_categories.article_id = comments.article_id', :conditions => ['articles_categories.category_id in (?)', category_ids]}.merge!(options) when 'Product' - {:select => 'distinct products.*', :joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id in (?)', category_ids]}.merge!(options) + if prod_cat_ids + {:select => 'distinct products.*', :joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id in (?) and products.product_category_id in (?)', category_ids, prod_cat_ids]}.merge!(options) + else + {:select => 'distinct products.*', :joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id in (?)', category_ids]}.merge!(options) + end when 'Article', 'Person', 'Community', 'Enterprise', 'Event' {:include => 'categories', :conditions => ['categories.id IN (?)', category_ids]}.merge!(options) else diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 5a267f0..b387112 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -9,7 +9,7 @@ class Enterprise < Organization extra_data_for_index :product_categories def product_categories - products.map{|p| p.product_category.full_name(' ') }.join(' ') + products.map{|p| p.category_full_name} end end diff --git a/app/models/environment_finder.rb b/app/models/environment_finder.rb index b686943..539478a 100644 --- a/app/models/environment_finder.rb +++ b/app/models/environment_finder.rb @@ -12,12 +12,22 @@ class EnvironmentFinder options.delete(:within) end + product_category = options.delete(:product_category) + product_category_ids = product_category.map_traversal(&:id) if product_category + if query.blank? - with_options :limit => limit, :order => 'created_at desc, id desc' do |finder| - @environment.send(asset).recent(limit) - end + if product_category && asset == :products + @environment.send(asset).find(:all, options.merge({:limit => limit, :order => 'created_at desc, id desc', :conditions => ['product_category_id in (?)', product_category_ids]})) + else + @environment.send(asset).find( :all, options.merge( {:limit => limit, :order => 'created_at desc, id desc'} ) ) + end else - @environment.send(asset).find_by_contents(query, {}, options) + if product_category && asset == :products + # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source + @environment.send(asset).find_by_contents(query, {}, options.merge({:conditions => 'product_category_id in (%s)' % product_category_ids.join(',') })) + else + @environment.send(asset).find_by_contents(query, {}, options) + end end end diff --git a/app/models/product.rb b/app/models/product.rb index 5876638..067ca3d 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -21,7 +21,7 @@ class Product < ActiveRecord::Base xss_terminate :only => [ :name, :description ] def category_full_name - product_category.full_name(" ") + product_category.full_name.split('/') end acts_as_having_image diff --git a/app/models/profile.rb b/app/models/profile.rb index 362504e..3eba59c 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -43,7 +43,7 @@ class Profile < ActiveRecord::Base self.extra_index_methods = [] def extra_data_for_index - self.class.extra_index_methods.map { |meth| meth.to_proc.call(self) } + self.class.extra_index_methods.map { |meth| meth.to_proc.call(self) }.flatten end def self.extra_data_for_index(sym = nil, &block) diff --git a/script/extract_sies_data.rb b/script/extract_sies_data.rb index e2d3698..4211d03 100644 --- a/script/extract_sies_data.rb +++ b/script/extract_sies_data.rb @@ -8,7 +8,7 @@ require 'active_support' require File.dirname(__FILE__) + "/../" + 'lib/noosfero/core_ext/string.rb' -LIMIT = (ENV['DUMP_ALL'] ? nil : 5) +LIMIT = (ENV['DUMP_ALL'] ? nil : 10) DUMP_ALL = LIMIT.nil? # To connect with the database that contains the data to be extracted cofigure it in the 'database_farejador.yml' with the name 'farejador' @@ -52,6 +52,8 @@ class Dumper def initialize @seq = 0 @seqs = {} + @r_seq = 0 + @r_seqs = {} end def pretty(str, alt = nil) @@ -72,7 +74,7 @@ categories[#{cat.id}] = cat#{@seq}.id @seq += 1 Category.find(:all, :conditions => { :id_mae => cat.id }).each do |child| - dump_category(child, cat) if (DUMP_ALL || (@seq <= LIMIT)) + dump_category(child, cat) #if (DUMP_ALL || (@seq <= LIMIT)) end end @@ -99,13 +101,19 @@ categories[#{cat.id}] = cat#{@seq}.id :lng => #{ent.long.inspect}, :geocode_precision => #{ent.geomodificou.inspect}, :data => { :id_sies => #{ent.id_sies.inspect} }, - :organization_info => OrganizationInfo.new(:contact_email => #{email.inspect}) }, + :contact_email => #{email.inspect}, + :categories => [cities[#{ent.id_cidade}]]}, [#{ent.products.map{|p| "{ :name => #{p.category.nome.inspect} , :product_category_id => categories[#{p.category.id}] }"}.join(', ')}], [#{ent.input_products.map{|p| "{ :product_category_id => categories[#{p.category.id}]}" }.join(', ')}])" end def dump_city(city) - puts "Region.create!(:name => #{city.cidade.inspect}, :parent => STATES[#{city.id.to_s[0..1]}], :lat => #{city.latitude}, :lng => #{city.longitude}, :environment => Environment.default)" + @r_seqs[city] = @r_seq + puts <<-EOF +city#{@r_seq} = new_region(#{city.cidade.inspect}, STATES[#{city.id.to_s[0..1]}], #{city.latitude}, #{city.longitude}) +cities[#{city.id}] = city#{@r_seq}.id + EOF + @r_seq += 1 end end @@ -126,10 +134,11 @@ Category.find(:all, :conditions => 'id_mae is null or id_mae = -1', :limit => LI dumper.dump_category(cat, nil) end -Enterprise.find(:all, :limit => LIMIT).each do |ent| - dumper.dump_enterprise(ent) -end - +puts "regions = {}" City.find(:all, :limit => LIMIT).each do |city| dumper.dump_city(city) end + +Enterprise.find(:all, :limit => LIMIT).each do |ent| + dumper.dump_enterprise(ent) +end diff --git a/script/fbes_populate_helper.rb b/script/fbes_populate_helper.rb index 2129a0e..9767c33 100644 --- a/script/fbes_populate_helper.rb +++ b/script/fbes_populate_helper.rb @@ -35,6 +35,11 @@ require File.dirname(__FILE__) + '/../config/environment' ProductCategory.find_by_path(path) || ProductCategory.create!(:name => name, :parent => parent, :environment => Environment.default) end + def new_region(name, parent, lat, lng) + path = (parent ? parent.path + '/' : '') + name.to_slug + Region.find_by_path(path) || Region.create!(:name => name, :parent => parent, :lat => lat, :lng => lng, :environment => Environment.default) + end + def new_ent(data, products, consumptions) posfix = '' count = 1 diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb index c4436d9..05b62b1 100644 --- a/test/functional/search_controller_test.rb +++ b/test/functional/search_controller_test.rb @@ -391,17 +391,6 @@ class SearchControllerTest < Test::Unit::TestCase assert_same recent, assigns(:results)[:articles] end - should 'list recent comments in the category' do - recent = [] - finger = CategoryFinder.new(@category) - finger.expects(:recent).with(anything).at_least_once - finger.expects(:recent).with('comments').returns(recent) - CategoryFinder.expects(:new).with(@category).returns(finger) - - get :category_index, :category_path => [ 'my-category' ] - assert_same recent, assigns(:results)[:comments] - end - should 'list most commented articles in the category' do most_commented = [] finger = CategoryFinder.new(@category) @@ -562,17 +551,6 @@ class SearchControllerTest < Test::Unit::TestCase assert_not_includes assigns(:results)[:enterprises], ent2 end - should 'display products with a given initial' do - ent = Enterprise.create!(:name => 'teste', :identifier => 'teste') - prod1 = ent.products.create!(:name => 'a beautiful product') - prod2 = ent.products.create!(:name => 'beautiful product (another)') - - get :directory, :asset => 'products', :initial => 'a' - - assert_includes assigns(:results)[:products], prod1 - assert_not_includes assigns(:results)[:products], prod2 - end - should 'display articles with a given initial' do person = create_user('teste').person art1 = person.articles.build(:name => 'an article to be found'); art1.save! @@ -632,24 +610,6 @@ class SearchControllerTest < Test::Unit::TestCase assert_not_includes assigns(:results)[:enterprises], ent4 end - should 'display products with a given initial, under a specific category' do - ent = Enterprise.create!(:name => 'teste', :identifier => 'teste') - ent.categories << @category - prod1 = ent.products.create!(:name => 'a beautiful product') - prod2 = ent.products.create!(:name => 'beautiful product (another)') - - ent2 = Enterprise.create!(:name => 'test2', :identifier => 'test2') - prod3 = ent2.products.create!(:name => 'another product') - prod4 = ent2.products.create!(:name => 'damn product (another)') - - get :directory, :asset => 'products', :initial => 'a', :category_path => [ 'my-category' ] - - assert_includes assigns(:results)[:products], prod1 - assert_not_includes assigns(:results)[:products], prod2 - assert_not_includes assigns(:results)[:products], prod3 - assert_not_includes assigns(:results)[:products], prod4 - end - should 'display articles with a given initial, under a specific category' do person = create_user('teste').person art1 = person.articles.build(:name => 'an article to be found'); art1.save! @@ -809,6 +769,48 @@ class SearchControllerTest < Test::Unit::TestCase end end + should 'list only categories with products' do + cat1 = ProductCategory.create!(:name => 'pc test 1', :environment => Environment.default) + cat2 = ProductCategory.create!(:name => 'pc test 2', :environment => Environment.default) + ent = Enterprise.create!(:name => 'test ent', :identifier => 'test_ent') + + cat1.products.create!(:name => 'prod test 1', :enterprise => ent) + + get :index, :find_in => 'products' + + assert_equal 1, assigns(:counts)[cat1.id][1] + assert_equal nil, assigns(:counts)[cat2.id] + end + + should 'not list ancestor if no product in it' do + cat1 = ProductCategory.create!(:name => 'pc test 1', :environment => Environment.default) + cat2 = ProductCategory.create!(:name => 'pc test 2', :environment => Environment.default, :parent => cat1) + ent = Enterprise.create!(:name => 'test ent', :identifier => 'test_ent') + + cat1.products.create!(:name => 'prod test 1', :enterprise => ent) + + get :index, :find_in => 'products' + + assert_equal 1, assigns(:counts)[cat1.id][1] + assert_equal nil, assigns(:counts)[cat2.id] + end + + should 'add hits of children in ancestor when it has products on results' do + cat1 = ProductCategory.create!(:name => 'pc test 1', :environment => Environment.default) + cat2 = ProductCategory.create!(:name => 'pc test 2', :environment => Environment.default, :parent => cat1) + ent = Enterprise.create!(:name => 'test ent', :identifier => 'test_ent') + + cat1.products.create!(:name => 'prod test 1', :enterprise => ent) + cat2.products.create!(:name => 'prod test 2', :enterprise => ent) + + get :index, :find_in => 'products' + + assert_equal 2, assigns(:counts)[cat1.id][1] + assert_equal 1, assigns(:counts)[cat2.id][1] + end + + should 'test somehow the display of events as calendar' + should 'provide calendar for events' do get :index, :find_in => [ 'events' ] assert_equal 0, assigns(:calendar).size % 7 diff --git a/test/unit/category_finder_test.rb b/test/unit/category_finder_test.rb index 3c6931f..7ec2a54 100644 --- a/test/unit/category_finder_test.rb +++ b/test/unit/category_finder_test.rb @@ -254,4 +254,40 @@ class CategoryFinderTest < ActiveSupport::TestCase assert_not_includes events, e2 end + should 'find person and enterprise in category by radius and region even without query' do + cat = Category.create!(:name => 'test category', :environment => Environment.default) + finder = CategoryFinder.new(cat) + + region = Region.create!(:name => 'r-test', :environment => Environment.default, :lat => 45.0, :lng => 45.0) + ent1 = Enterprise.create!(:name => 'test 1', :identifier => 'test1', :lat => 45.0, :lng => 45.0, :categories => [cat]) + p1 = create_user('test2').person + p1.name = 'test 2'; p1.lat = 45.0; p1.lng = 45.0; p1.categories = [cat]; p1.save! + ent2 = Enterprise.create!(:name => 'test 3', :identifier => 'test3', :lat => 30.0, :lng => 30.0, :categories => [cat]) + p2 = create_user('test4').person + p2.name = 'test 4'; p2.lat = 30.0; p2.lng = 30.0; p2.categories = [cat]; p2.save! + + ents = finder.find(:enterprises, nil, :within => 10, :region => region.id) + people = finder.find(:people, nil, :within => 10, :region => region.id) + + assert_includes ents, ent1 + assert_not_includes ents, ent2 + assert_includes people, p1 + assert_not_includes people, p2 + end + + should 'find products in category wihin product category' do + cat = Category.create!(:name => 'test category', :environment => Environment.default) + finder = CategoryFinder.new(cat) + + prod_cat = ProductCategory.create!(:name => 'test product category', :environment => Environment.default) + ent = Enterprise.create!(:name => 'test enterprise', :identifier => 'test_ent', :categories => [cat]) + prod1 = ent.products.create!(:name => 'test product 1', :product_category => prod_cat) + prod2 = ent.products.create!(:name => 'test product 2') + + prods = finder.find(:products, nil, :product_category => prod_cat) + + assert_includes prods, prod1 + assert_not_includes prods, prod2 + end + end diff --git a/test/unit/environment_finder_test.rb b/test/unit/environment_finder_test.rb index 2082652..3cc37d4 100644 --- a/test/unit/environment_finder_test.rb +++ b/test/unit/environment_finder_test.rb @@ -131,4 +131,64 @@ class EnvironmentFinderTest < ActiveSupport::TestCase assert_not_includes people, p2 end + should 'find person and enterprise by radius and region even without query' do + finder = EnvironmentFinder.new(Environment.default) + + region = Region.create!(:name => 'r-test', :environment => Environment.default, :lat => 45.0, :lng => 45.0) + ent1 = Enterprise.create!(:name => 'test 1', :identifier => 'test1', :lat => 45.0, :lng => 45.0) + p1 = create_user('test2').person + p1.name = 'test 2'; p1.lat = 45.0; p1.lng = 45.0; p1.save! + ent2 = Enterprise.create!(:name => 'test 3', :identifier => 'test3', :lat => 30.0, :lng => 30.0) + p2 = create_user('test4').person + p2.name = 'test 4'; p2.lat = 30.0; p2.lng = 30.0; p2.save! + + ents = finder.find(:enterprises, nil, :within => 10, :region => region.id) + people = finder.find(:people, nil, :within => 10, :region => region.id) + + assert_includes ents, ent1 + assert_not_includes ents, ent2 + assert_includes people, p1 + assert_not_includes people, p2 + end + + should 'find products wihin product category' do + finder = EnvironmentFinder.new(Environment.default) + cat = ProductCategory.create!(:name => 'test category', :environment => Environment.default) + ent = Enterprise.create!(:name => 'test enterprise', :identifier => 'test_ent') + prod1 = ent.products.create!(:name => 'test product 1', :product_category => cat) + prod2 = ent.products.create!(:name => 'test product 2') + + prods = finder.find(:products, nil, :product_category => cat) + + assert_includes prods, prod1 + assert_not_includes prods, prod2 + end + + should 'find products wihin product category with query' do + finder = EnvironmentFinder.new(Environment.default) + cat = ProductCategory.create!(:name => 'test category', :environment => Environment.default) + ent = Enterprise.create!(:name => 'test enterprise', :identifier => 'test_ent') + prod1 = ent.products.create!(:name => 'test product a_word 1', :product_category => cat) + prod2 = ent.products.create!(:name => 'test product b_word 1', :product_category => cat) + prod3 = ent.products.create!(:name => 'test product a_word 2') + prod4 = ent.products.create!(:name => 'test product b_word 2') + + prods = finder.find(:products, 'a_word', :product_category => cat) + + assert_includes prods, prod1 + assert_not_includes prods, prod2 + assert_not_includes prods, prod3 + assert_not_includes prods, prod4 + end + + should 'find in order of creation' do + finder = EnvironmentFinder.new(Environment.default) + ent1 = Enterprise.create!(:name => 'test enterprise 1', :identifier => 'test_ent1') + ent2 = Enterprise.create!(:name => 'test enterprise 2', :identifier => 'test_ent2') + + ents = finder.find(:enterprises, nil) + + assert ents.index(ent2) < ents.index(ent1), "expected #{ents.index(ent2)} be smaller than #{ents.index(ent1)}" + end + end diff --git a/test/unit/product_test.rb b/test/unit/product_test.rb index cc3d232..4e9c2a0 100644 --- a/test/unit/product_test.rb +++ b/test/unit/product_test.rb @@ -69,11 +69,11 @@ class ProductTest < Test::Unit::TestCase should 'calculate catagory full name' do cat = mock - cat.expects(:full_name).returns('A B C') + cat.expects(:full_name).returns('A/B/C') p = Product.new p.expects(:product_category).returns(cat) - assert_equal 'A B C', p.category_full_name + assert_equal ['A','B','C'], p.category_full_name end should 'be indexed by category full name' do -- libgit2 0.21.2