Commit cc17d60a3936837afdc7a2dfcefe51acbe27eb5f

Authored by MoisesMachado
1 parent cdde5e0b

ActionItem253: fixed a bug where article categorized in more than one categories…

… in a given subtree is returned twice when searchin for the top category


git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@1716 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/public/search_controller.rb
@@ -38,7 +38,7 @@ class SearchController < ApplicationController @@ -38,7 +38,7 @@ class SearchController < ApplicationController
38 def action_category 38 def action_category
39 @recent_articles = @finder.recent('articles') 39 @recent_articles = @finder.recent('articles')
40 @recent_comments = @finder.recent('comments') 40 @recent_comments = @finder.recent('comments')
41 - @most_commented_articles = category.most_commented_articles 41 + @most_commented_articles = @finder.most_commented_articles
42 end 42 end
43 alias :action_region :action_category 43 alias :action_region :action_category
44 44
@@ -76,7 +76,7 @@ class SearchController < ApplicationController @@ -76,7 +76,7 @@ class SearchController < ApplicationController
76 76
77 # view the summary of one category 77 # view the summary of one category
78 def category_index 78 def category_index
79 - send('action_' + @category.class.name.underscore) 79 + send('action_' + category.class.name.underscore)
80 end 80 end
81 attr_reader :category 81 attr_reader :category
82 82
app/models/category_finder.rb
@@ -24,33 +24,49 @@ class CategoryFinder @@ -24,33 +24,49 @@ class CategoryFinder
24 end 24 end
25 25
26 def products(query='*', options={}) 26 def products(query='*', options={})
27 - Product.find_by_contents(query, {}, {:select => 'products.*', :joins => 'inner join categories_profiles on products.enterprise_id = categories_profiles.profile_id', :conditions => ['categories_profiles.category_id in (?)', category_ids]}.merge!(options)) 27 + find_in_categorized(Product, query, options)
28 end 28 end
29 29
30 def comments(query='*', options={}) 30 def comments(query='*', options={})
31 - Comment.find_by_contents(query, {}, {:select => 'comments.*', :joins => 'inner join articles_categories on articles_categories.article_id = comments.article_id', :conditions => ['articles_categories.category_id in (?)', category_ids]}.merge!(options)) 31 + find_in_categorized(Comment, query, options)
32 end 32 end
33 33
34 def recent(asset, limit = 10) 34 def recent(asset, limit = 10)
35 - table = case asset  
36 - when 'people', 'communities', 'enterprises'  
37 - 'profiles'  
38 - else  
39 - asset  
40 - end  
41 -  
42 - with_options :limit => limit, :order => "created_at desc, #{table}.id desc" do |finder|  
43 - finder.send(asset, '*', {})  
44 - end 35 + asset_class(asset).find(:all, options_for_find(asset_class(asset), {:limit => limit, :order => "created_at desc, #{asset_table(asset)}.id desc"}))
45 end 36 end
46 37
47 def count(asset) 38 def count(asset)
48 - send(asset).size 39 + asset_class(asset).count(:all, options_for_find(asset_class(asset)))
  40 + end
  41 +
  42 + def most_commented_articles(limit=10)
  43 + Article.find(:all, options_for_find(Article, :limit => limit, :order => 'comments_count DESC'))
49 end 44 end
50 45
51 protected 46 protected
52 47
53 def find_in_categorized(klass, query, options={}) 48 def find_in_categorized(klass, query, options={})
54 - klass.find_by_contents(query, {}, {:include => 'categories', :conditions => ['categories.id IN (?)', category_ids]}.merge!(options)) 49 + klass.find_by_contents(query, {}, options_for_find(klass, options)).uniq
  50 + end
  51 +
  52 + def options_for_find(klass, options={})
  53 + case klass.name
  54 + when 'Comment'
  55 + {: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)
  56 + when 'Product'
  57 + {: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)
  58 + when 'Article', 'Person', 'Community', 'Enterprise'
  59 + {:include => 'categories', :conditions => ['categories.id IN (?)', category_ids]}.merge!(options)
  60 + else
  61 + raise "unreconized class #{klass.name}"
  62 + end
  63 + end
  64 +
  65 + def asset_class(asset)
  66 + asset.to_s.singularize.camelize.constantize
  67 + end
  68 +
  69 + def asset_table(asset)
  70 + asset_class(asset).table_name
55 end 71 end
56 end 72 end
test/functional/search_controller_test.rb
@@ -31,9 +31,9 @@ class SearchControllerTest < Test::Unit::TestCase @@ -31,9 +31,9 @@ class SearchControllerTest < Test::Unit::TestCase
31 31
32 should 'search with filtered query' do 32 should 'search with filtered query' do
33 @controller.expects(:locale).returns('pt_BR').at_least_once 33 @controller.expects(:locale).returns('pt_BR').at_least_once
34 - @controller.expects(:search).with(anything, 'carne vaca').at_least_once  
35 - @controller.expects(:search).with(anything, 'a carne da vaca').never  
36 get 'index', :query => 'a carne da vaca' 34 get 'index', :query => 'a carne da vaca'
  35 +
  36 + assert_equal 'carne vaca', assigns('filtered_query')
37 end 37 end
38 38
39 should 'search only in specified types of content' do 39 should 'search only in specified types of content' do
@@ -250,7 +250,7 @@ class SearchControllerTest < Test::Unit::TestCase @@ -250,7 +250,7 @@ class SearchControllerTest < Test::Unit::TestCase
250 p2 = create_user('test2').person 250 p2 = create_user('test2').person
251 251
252 get :assets, :asset => 'people', :category_path => [ 'my-category' ] 252 get :assets, :asset => 'people', :category_path => [ 'my-category' ]
253 - assert_equal [p1], assigns(:results)[:people].instance_variable_get('@results') 253 + assert_equal [p1], assigns(:results)[:people]
254 end 254 end
255 255
256 should 'find communities' do 256 should 'find communities' do
@@ -293,7 +293,7 @@ class SearchControllerTest < Test::Unit::TestCase @@ -293,7 +293,7 @@ class SearchControllerTest < Test::Unit::TestCase
293 293
294 get :assets, :asset => 'communities', :category_path => [ 'my-category' ] 294 get :assets, :asset => 'communities', :category_path => [ 'my-category' ]
295 295
296 - assert_equal [c3, c1], assigns(:results)[:communities].instance_variable_get('@results') 296 + assert_equal [c3, c1], assigns(:results)[:communities]
297 end 297 end
298 298
299 should 'find products' do 299 should 'find products' do
@@ -379,7 +379,7 @@ class SearchControllerTest < Test::Unit::TestCase @@ -379,7 +379,7 @@ class SearchControllerTest < Test::Unit::TestCase
379 } 379 }
380 names.each do |thing,description| 380 names.each do |thing,description|
381 assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => "find_in[]", :value => thing.to_s, :checked => 'checked' } 381 assert_tag :tag => 'input', :attributes => { :type => 'checkbox', :name => "find_in[]", :value => thing.to_s, :checked => 'checked' }
382 - assert_tag :tag => 'span', :content => description 382 + assert_tag :tag => 'label', :content => description
383 end 383 end
384 end 384 end
385 385
@@ -435,7 +435,10 @@ class SearchControllerTest < Test::Unit::TestCase @@ -435,7 +435,10 @@ class SearchControllerTest < Test::Unit::TestCase
435 should 'list recent articles in the category' do 435 should 'list recent articles in the category' do
436 @controller.expects(:category).returns(@category).at_least_once 436 @controller.expects(:category).returns(@category).at_least_once
437 recent = [] 437 recent = []
438 - @category.expects(:recent_articles).returns(recent) 438 + finder = CategoryFinder.new(@category)
  439 + finder.expects(:recent).with('comments').returns(recent)
  440 + finder.expects(:recent).with('articles').returns(recent)
  441 + CategoryFinder.expects(:new).with(@category).returns(finder)
439 442
440 get :category_index, :category_path => [ 'my-category' ] 443 get :category_index, :category_path => [ 'my-category' ]
441 assert_same recent, assigns(:recent_articles) 444 assert_same recent, assigns(:recent_articles)
@@ -444,7 +447,10 @@ class SearchControllerTest < Test::Unit::TestCase @@ -444,7 +447,10 @@ class SearchControllerTest < Test::Unit::TestCase
444 should 'list recent comments in the category' do 447 should 'list recent comments in the category' do
445 @controller.expects(:category).returns(@category).at_least_once 448 @controller.expects(:category).returns(@category).at_least_once
446 recent = [] 449 recent = []
447 - @category.expects(:recent_comments).returns(recent) 450 + finder = CategoryFinder.new(@category)
  451 + finder.expects(:recent).with('comments').returns(recent)
  452 + finder.expects(:recent).with('articles').returns(recent)
  453 + CategoryFinder.expects(:new).with(@category).returns(finder)
448 454
449 get :category_index, :category_path => [ 'my-category' ] 455 get :category_index, :category_path => [ 'my-category' ]
450 assert_same recent, assigns(:recent_comments) 456 assert_same recent, assigns(:recent_comments)
@@ -453,7 +459,9 @@ class SearchControllerTest < Test::Unit::TestCase @@ -453,7 +459,9 @@ class SearchControllerTest < Test::Unit::TestCase
453 should 'list most commented articles in the category' do 459 should 'list most commented articles in the category' do
454 @controller.expects(:category).returns(@category).at_least_once 460 @controller.expects(:category).returns(@category).at_least_once
455 most_commented = [] 461 most_commented = []
456 - @category.expects(:most_commented_articles).returns(most_commented) 462 + finder = CategoryFinder.new(@category)
  463 + finder.expects(:most_commented_articles).returns(most_commented)
  464 + CategoryFinder.expects(:new).with(@category).returns(finder)
457 465
458 get :category_index, :category_path => [ 'my-category' ] 466 get :category_index, :category_path => [ 'my-category' ]
459 assert_same most_commented, assigns(:most_commented_articles) 467 assert_same most_commented, assigns(:most_commented_articles)
@@ -509,7 +517,7 @@ class SearchControllerTest < Test::Unit::TestCase @@ -509,7 +517,7 @@ class SearchControllerTest < Test::Unit::TestCase
509 child = Category.create!(:name => "Child Category", :environment => Environment.default, :parent => parent) 517 child = Category.create!(:name => "Child Category", :environment => Environment.default, :parent => parent)
510 518
511 get :index, :category_path => [ 'parent-category', 'child-category' ], :query => 'a sample search' 519 get :index, :category_path => [ 'parent-category', 'child-category' ], :query => 'a sample search'
512 - assert_tag :tag => 'h2', :content => /Search results for "a sample search" in "Child Category"/ 520 + assert_tag :tag => 'h1', :content => /Search results for "a sample search" in "Child Category"/
513 end 521 end
514 522
515 should 'search in categoty hierachy' do 523 should 'search in categoty hierachy' do
test/unit/category_finder_test.rb
@@ -88,9 +88,9 @@ class CategoryFinderTest < ActiveSupport::TestCase @@ -88,9 +88,9 @@ class CategoryFinderTest < ActiveSupport::TestCase
88 end 88 end
89 89
90 should 'search in category hierarchy' do 90 should 'search in category hierarchy' do
91 - parent = Category.create!(:name => 'child category', :environment => Environment.default) 91 + parent = Category.create!(:name => 'parent category', :environment => Environment.default)
92 child = Category.create!(:name => 'child category', :environment => Environment.default, :parent => parent) 92 child = Category.create!(:name => 'child category', :environment => Environment.default, :parent => parent)
93 - p1 = create_user('people_1').person; p1.name = 'a beautiful person'; p1.categories << parent; p1.save! 93 + p1 = create_user('people_1').person; p1.name = 'a beautiful person'; p1.categories << child; p1.save!
94 94
95 f = CategoryFinder.new(parent) 95 f = CategoryFinder.new(parent)
96 assert_includes f.people, p1 96 assert_includes f.people, p1
@@ -105,8 +105,8 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase @@ -105,8 +105,8 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase
105 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category]) 105 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category])
106 ent2 = Enterprise.create!(:name => 'teste2', :identifier => 'teste2', :categories => [@category]) 106 ent2 = Enterprise.create!(:name => 'teste2', :identifier => 'teste2', :categories => [@category])
107 recent = @finder.recent('enterprises', 1) 107 recent = @finder.recent('enterprises', 1)
108 - assert_includes recent, ent1  
109 - assert_not_includes recent, ent2 108 + assert_includes recent, ent2
  109 + assert_not_includes recent, ent1
110 end 110 end
111 111
112 should 'count entrprises' do 112 should 'count entrprises' do
@@ -114,4 +114,47 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase @@ -114,4 +114,47 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase
114 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category]) 114 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category])
115 assert_equal count+1, @finder.count('enterprises') 115 assert_equal count+1, @finder.count('enterprises')
116 end 116 end
  117 +
  118 + should 'not list more people than limit' do
  119 + p1 = create_user('test1').person; p1.categories << @category
  120 + p2 = create_user('test2').person; p2.categories << @category
  121 + recent = @finder.recent('people', 1)
  122 + assert_includes recent, p2
  123 + assert_not_includes recent, p1
  124 + end
  125 +
  126 + should 'list recent articles' do
  127 + person = create_user('teste').person
  128 + art1 = person.articles.build(:name => 'an article to be found'); art1.categories << @category; art1.save!
  129 +
  130 + art2 = person.articles.build(:name => 'another article to be found'); art2.categories << @category; art2.save!
  131 +
  132 + result = @finder.recent('articles', 1)
  133 + assert_includes result, art2
  134 + assert_not_includes result, art1
  135 + end
  136 +
  137 + should 'not return the same result twice' do
  138 + parent = Category.create!(:name => 'parent category', :environment => Environment.default)
  139 + child = Category.create!(:name => 'child category', :environment => Environment.default, :parent => parent)
  140 + p1 = create_user('people_1').person; p1.name = 'a beautiful person'; p1.categories << child; p1.save!
  141 + p1.categories << parent; p1.save!
  142 +
  143 + f = CategoryFinder.new(parent)
  144 + result = f.people
  145 + assert_equal 1, result.size
  146 + end
  147 +
  148 + should 'return most commented articles' do
  149 + Article.delete_all
  150 +
  151 + person = create_user('testuser').person
  152 + articles = (1..4).map {|n| a = person.articles.build(:name => "art #{n}", :categories => [@category]); a.save!; a }
  153 +
  154 + 2.times { articles[0].comments.build(:title => 'test', :body => 'asdsad', :author => person).save! }
  155 + 4.times { articles[1].comments.build(:title => 'test', :body => 'asdsad', :author => person).save! }
  156 +
  157 + # should respect the order (more commented comes first)
  158 + assert_equal [articles[1], articles[0]], @finder.most_commented_articles(2)
  159 + end
117 end 160 end