Commit cc17d60a3936837afdc7a2dfcefe51acbe27eb5f
1 parent
cdde5e0b
Exists in
master
and in
22 other branches
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
Showing
4 changed files
with
96 additions
and
29 deletions
Show diff stats
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 < ActiveSupport::TestCase | @@ -105,8 +105,8 @@ class CategoryFinderTest < 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 < ActiveSupport::TestCase | @@ -114,4 +114,47 @@ class CategoryFinderTest < 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 |