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 38 def action_category
39 39 @recent_articles = @finder.recent('articles')
40 40 @recent_comments = @finder.recent('comments')
41   - @most_commented_articles = category.most_commented_articles
  41 + @most_commented_articles = @finder.most_commented_articles
42 42 end
43 43 alias :action_region :action_category
44 44  
... ... @@ -76,7 +76,7 @@ class SearchController < ApplicationController
76 76  
77 77 # view the summary of one category
78 78 def category_index
79   - send('action_' + @category.class.name.underscore)
  79 + send('action_' + category.class.name.underscore)
80 80 end
81 81 attr_reader :category
82 82  
... ...
app/models/category_finder.rb
... ... @@ -24,33 +24,49 @@ class CategoryFinder
24 24 end
25 25  
26 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 28 end
29 29  
30 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 32 end
33 33  
34 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 36 end
46 37  
47 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 44 end
50 45  
51 46 protected
52 47  
53 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 71 end
56 72 end
... ...
test/functional/search_controller_test.rb
... ... @@ -31,9 +31,9 @@ class SearchControllerTest < Test::Unit::TestCase
31 31  
32 32 should 'search with filtered query' do
33 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 34 get 'index', :query => 'a carne da vaca'
  35 +
  36 + assert_equal 'carne vaca', assigns('filtered_query')
37 37 end
38 38  
39 39 should 'search only in specified types of content' do
... ... @@ -250,7 +250,7 @@ class SearchControllerTest < Test::Unit::TestCase
250 250 p2 = create_user('test2').person
251 251  
252 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 254 end
255 255  
256 256 should 'find communities' do
... ... @@ -293,7 +293,7 @@ class SearchControllerTest < Test::Unit::TestCase
293 293  
294 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 297 end
298 298  
299 299 should 'find products' do
... ... @@ -379,7 +379,7 @@ class SearchControllerTest < Test::Unit::TestCase
379 379 }
380 380 names.each do |thing,description|
381 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 383 end
384 384 end
385 385  
... ... @@ -435,7 +435,10 @@ class SearchControllerTest < Test::Unit::TestCase
435 435 should 'list recent articles in the category' do
436 436 @controller.expects(:category).returns(@category).at_least_once
437 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 443 get :category_index, :category_path => [ 'my-category' ]
441 444 assert_same recent, assigns(:recent_articles)
... ... @@ -444,7 +447,10 @@ class SearchControllerTest < Test::Unit::TestCase
444 447 should 'list recent comments in the category' do
445 448 @controller.expects(:category).returns(@category).at_least_once
446 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 455 get :category_index, :category_path => [ 'my-category' ]
450 456 assert_same recent, assigns(:recent_comments)
... ... @@ -453,7 +459,9 @@ class SearchControllerTest < Test::Unit::TestCase
453 459 should 'list most commented articles in the category' do
454 460 @controller.expects(:category).returns(@category).at_least_once
455 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 466 get :category_index, :category_path => [ 'my-category' ]
459 467 assert_same most_commented, assigns(:most_commented_articles)
... ... @@ -509,7 +517,7 @@ class SearchControllerTest < Test::Unit::TestCase
509 517 child = Category.create!(:name => "Child Category", :environment => Environment.default, :parent => parent)
510 518  
511 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 521 end
514 522  
515 523 should 'search in categoty hierachy' do
... ...
test/unit/category_finder_test.rb
... ... @@ -88,9 +88,9 @@ class CategoryFinderTest < ActiveSupport::TestCase
88 88 end
89 89  
90 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 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 95 f = CategoryFinder.new(parent)
96 96 assert_includes f.people, p1
... ... @@ -105,8 +105,8 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase
105 105 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category])
106 106 ent2 = Enterprise.create!(:name => 'teste2', :identifier => 'teste2', :categories => [@category])
107 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 110 end
111 111  
112 112 should 'count entrprises' do
... ... @@ -114,4 +114,47 @@ class CategoryFinderTest &lt; ActiveSupport::TestCase
114 114 ent1 = Enterprise.create!(:name => 'teste1', :identifier => 'teste1', :categories => [@category])
115 115 assert_equal count+1, @finder.count('enterprises')
116 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 160 end
... ...