Commit 1f8a1560a9a7e85142c243da5f44a77b9eda08fb
Exists in
master
and in
28 other branches
Merge commit 'refs/merge-requests/50' of git://gitorious.org/noosfero/noosfero
Showing
13 changed files
with
291 additions
and
8 deletions
Show diff stats
app/controllers/public/browse_controller.rb
| ... | ... | @@ -6,6 +6,8 @@ class BrowseController < PublicController |
| 6 | 6 | more_recent |
| 7 | 7 | more_active |
| 8 | 8 | more_popular |
| 9 | + more_comments | |
| 10 | + more_views | |
| 9 | 11 | ) |
| 10 | 12 | |
| 11 | 13 | def per_page |
| ... | ... | @@ -36,6 +38,18 @@ class BrowseController < PublicController |
| 36 | 38 | @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) |
| 37 | 39 | end |
| 38 | 40 | |
| 41 | + def contents | |
| 42 | + @filter = filter | |
| 43 | + @title = self.filter_description(params[:action] + '_' + @filter ) | |
| 44 | + | |
| 45 | + @results = @environment.articles.published.text_articles.send(@filter) | |
| 46 | + | |
| 47 | + if !params[:query].blank? | |
| 48 | + @results = @results.find_by_contents(params[:query]) | |
| 49 | + end | |
| 50 | + @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) | |
| 51 | + end | |
| 52 | + | |
| 39 | 53 | protected |
| 40 | 54 | |
| 41 | 55 | def filter |
| ... | ... | @@ -54,6 +68,9 @@ class BrowseController < PublicController |
| 54 | 68 | 'communities_more_recent' => _('More recent communities'), |
| 55 | 69 | 'communities_more_active' => _('More active communities'), |
| 56 | 70 | 'communities_more_popular' => _('More popular communities'), |
| 71 | + 'contents_more_recent' => _('More recent contents'), | |
| 72 | + 'contents_more_views' => _('Most viewed contents'), | |
| 73 | + 'contents_more_comments' => _('Most commented contents'), | |
| 57 | 74 | }[str] || str |
| 58 | 75 | end |
| 59 | 76 | ... | ... |
app/helpers/application_helper.rb
| ... | ... | @@ -1134,6 +1134,17 @@ module ApplicationHelper |
| 1134 | 1134 | link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') |
| 1135 | 1135 | end |
| 1136 | 1136 | |
| 1137 | + def browse_contents_menu | |
| 1138 | + links = [ | |
| 1139 | + {s_('contents|More Comments') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_comments'})}}, | |
| 1140 | + {s_('contents|More Views') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_views'})}}, | |
| 1141 | + {s_('contents|More Recent') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_recent'})}} | |
| 1142 | + ] | |
| 1143 | + | |
| 1144 | + link_to(content_tag(:span, _('Contents'), :class => 'icon-blog'), {:controller => "browse", :action => 'contents'}, :id => 'submenu-contents') + | |
| 1145 | + link_to(content_tag(:span, _('Contents Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger') | |
| 1146 | + end | |
| 1147 | + | |
| 1137 | 1148 | def pagination_links(collection, options={}) |
| 1138 | 1149 | options = {:prev_label => '« ' + _('Previous'), :next_label => _('Next') + ' »'}.merge(options) |
| 1139 | 1150 | will_paginate(collection, options) | ... | ... |
app/models/article.rb
| ... | ... | @@ -355,11 +355,20 @@ class Article < ActiveRecord::Base |
| 355 | 355 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
| 356 | 356 | end |
| 357 | 357 | |
| 358 | + def self.text_article_types | |
| 359 | + ['TextArticle', 'TextileArticle', 'TinyMceArticle'] | |
| 360 | + end | |
| 361 | + | |
| 358 | 362 | named_scope :published, :conditions => { :published => true } |
| 359 | 363 | named_scope :folders, :conditions => { :type => folder_types} |
| 360 | 364 | named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types] |
| 361 | 365 | named_scope :galleries, :conditions => { :type => 'Gallery' } |
| 362 | 366 | named_scope :images, :conditions => { :is_image => true } |
| 367 | + named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] | |
| 368 | + | |
| 369 | + named_scope :more_comments, :order => "comments_count DESC" | |
| 370 | + named_scope :more_views, :order => "hits DESC" | |
| 371 | + named_scope :more_recent, :order => "created_at DESC" | |
| 363 | 372 | |
| 364 | 373 | def self.display_filter(user, profile) |
| 365 | 374 | return {:conditions => ['published = ?', true]} if !user |
| ... | ... | @@ -528,6 +537,28 @@ class Article < ActiveRecord::Base |
| 528 | 537 | end |
| 529 | 538 | end |
| 530 | 539 | |
| 540 | + def more_comments_label | |
| 541 | + amount = self.comments_count | |
| 542 | + { | |
| 543 | + 0 => _('no comments'), | |
| 544 | + 1 => _('one comment') | |
| 545 | + }[amount] || _("%s comments") % amount | |
| 546 | + | |
| 547 | + end | |
| 548 | + | |
| 549 | + def more_views_label | |
| 550 | + amount = self.hits | |
| 551 | + { | |
| 552 | + 0 => _('no views'), | |
| 553 | + 1 => _('one view') | |
| 554 | + }[amount] || _("%s views") % amount | |
| 555 | + | |
| 556 | + end | |
| 557 | + | |
| 558 | + def more_recent_label | |
| 559 | + _('Created at: ') | |
| 560 | + end | |
| 561 | + | |
| 531 | 562 | private |
| 532 | 563 | |
| 533 | 564 | def sanitize_tag_list | ... | ... |
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +<li class="<%= 'browse-results-type-content ' + icon_for_article(result) %>"> | |
| 2 | + <strong><%= link_to(result.title, result.view_url) %></strong> | |
| 3 | + <div class="item_meta"> | |
| 4 | + <span class="item_by"> | |
| 5 | + <%= _('by %s') % link_to(result.author.name, result.author.url) %> | |
| 6 | + </span> | |
| 7 | + <span class="extra-info"> | |
| 8 | + <%= (@filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label')) %> | |
| 9 | + </span> | |
| 10 | + </div> | |
| 11 | +</li> | ... | ... |
app/views/browse/_display_results.rhtml
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | <% end %> |
| 9 | 9 | <ul class='common-profile-list-block'> |
| 10 | 10 | <% @results.each do |result| %> |
| 11 | - <%= render :partial => partial_for_class(result.class), :locals => {:profile => result} %> | |
| 11 | + <%= render :partial => partial_for_class(result.class), :locals => {:result => result} %> | |
| 12 | 12 | <% end %> |
| 13 | 13 | </ul> |
| 14 | 14 | <br style='clear: both;'> | ... | ... |
app/views/browse/_person.rhtml
| 1 | -<%= profile_image_link profile, :portrait, 'li', | |
| 2 | - "<span class='adr'>#{profile.city}</span>" + | |
| 3 | - (@filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label')) %> | |
| 1 | +<%= profile_image_link result, :portrait, 'li', | |
| 2 | + "<span class='adr'>#{result.city}</span>" + | |
| 3 | + (@filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label')) %> | ... | ... |
app/views/browse/_profile.rhtml
| 1 | -<%= profile_image_link profile, :portrait, 'li', @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> | |
| 1 | +<%= profile_image_link result, :portrait, 'li', @filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label') %> | ... | ... |
features/browse.feature
| ... | ... | @@ -84,3 +84,26 @@ Feature: browse |
| 84 | 84 | And I should not see "Pedro Silva" |
| 85 | 85 | And I should not see "Paulo Neto" |
| 86 | 86 | And I should not see "Community Silva" |
| 87 | + | |
| 88 | + @selenium | |
| 89 | + Scenario: Show contents browse menu | |
| 90 | + Given I should not see "More Comments" | |
| 91 | + And I should not see "More Views" | |
| 92 | + And I should not see "More Recent" | |
| 93 | + When I click "#submenu-contents-trigger" | |
| 94 | + Then I should see "More Comments" | |
| 95 | + And I should see "More Views" | |
| 96 | + And I should see "More Recent" | |
| 97 | + | |
| 98 | + Scenario: Browse contents by query | |
| 99 | + Given the following articles | |
| 100 | + | owner | name | body | | |
| 101 | + | joaosilva | Bees can fly | this is an article | | |
| 102 | + | joaosilva | Bees and ants are insects | this is another article | | |
| 103 | + | joaosilva | Ants are small | this is another article | | |
| 104 | + When I go to /browse/contents | |
| 105 | + And I fill in "bees" for "query" | |
| 106 | + And I press "Search" | |
| 107 | + Then I should see "Bees can fly" | |
| 108 | + And I should see "Bees and ants are insects" | |
| 109 | + And I should not see "Ants are small" | ... | ... |
public/designs/themes/base/navigation.rhtml
public/stylesheets/application.css
| ... | ... | @@ -4503,23 +4503,30 @@ h1#agenda-title { |
| 4503 | 4503 | } |
| 4504 | 4504 | |
| 4505 | 4505 | .controller-search #content .search-results-type-article li, |
| 4506 | -.controller-search #content .search-results-type-event li { | |
| 4506 | +.controller-search #content .search-results-type-event li, | |
| 4507 | +.controller-browse #content li.browse-results-type-content { | |
| 4507 | 4508 | padding: 0px 0px 4px 20px; |
| 4508 | 4509 | background-repeat: no-repeat; |
| 4509 | 4510 | border-color: transparent; |
| 4510 | 4511 | } |
| 4511 | 4512 | |
| 4512 | 4513 | .controller-search #content .search-results-type-article li:hover, |
| 4513 | -.controller-search #content .search-results-type-event li:hover { | |
| 4514 | +.controller-search #content .search-results-type-event li:hover, | |
| 4515 | +.controller-browse #content li.browse-results-type-content:hover { | |
| 4514 | 4516 | background-color: transparent; |
| 4515 | 4517 | } |
| 4516 | 4518 | |
| 4517 | 4519 | .controller-search .search-results-type-article .item_meta, |
| 4518 | -.controller-search .search-results-type-event .item_meta { | |
| 4520 | +.controller-search .search-results-type-event .item_meta, | |
| 4521 | +.controller-browse .browse-results-type-content .item_meta { | |
| 4519 | 4522 | font-size: 10px; |
| 4520 | 4523 | color: #888; |
| 4521 | 4524 | } |
| 4522 | 4525 | |
| 4526 | +.controller-browse .browse-results-type-content .item_meta span { | |
| 4527 | + width: auto; | |
| 4528 | +} | |
| 4529 | + | |
| 4523 | 4530 | .search-results-type-article.search-results-innerbox { |
| 4524 | 4531 | overflow: auto; |
| 4525 | 4532 | } | ... | ... |
test/functional/browse_controller_test.rb
| ... | ... | @@ -19,7 +19,10 @@ class BrowseControllerTest < Test::Unit::TestCase |
| 19 | 19 | user.stubs(:email).returns('some@test.com') |
| 20 | 20 | user.stubs(:save!).returns(true) |
| 21 | 21 | Person.any_instance.stubs(:user).returns(user) |
| 22 | + @profile = create_user('testinguser').person | |
| 23 | + Article.destroy_all | |
| 22 | 24 | end |
| 25 | + attr_reader :profile | |
| 23 | 26 | |
| 24 | 27 | should 'search for people' do |
| 25 | 28 | Person.delete_all |
| ... | ... | @@ -274,4 +277,98 @@ class BrowseControllerTest < Test::Unit::TestCase |
| 274 | 277 | assert_not_includes assigns(:results), p1 |
| 275 | 278 | end |
| 276 | 279 | |
| 280 | + should 'search for contents' do | |
| 281 | + small = create(TinyMceArticle, :name => 'Testing article', :body => 'A small article for testing', :profile => profile) | |
| 282 | + create(TinyMceArticle, :name => 'Testing article 2', :body => 'A big article for testing', :profile => profile) | |
| 283 | + | |
| 284 | + get :contents, :query => 'small' | |
| 285 | + assert_equal [small], assigns(:results) | |
| 286 | + end | |
| 287 | + | |
| 288 | + should 'list all contents ordered by more recent by default' do | |
| 289 | + c1 = create(TinyMceArticle, :name => 'Testing article 1', :body => 'Article body 1', :profile => profile, :created_at => DateTime.now - 2) | |
| 290 | + c2 = create(TinyMceArticle, :name => 'Testing article 2', :body => 'Article body 2', :profile => profile, :created_at => DateTime.now - 1) | |
| 291 | + c3 = create(TinyMceArticle, :name => 'Testing article 3', :body => 'Article body 3', :profile => profile) | |
| 292 | + | |
| 293 | + get :contents | |
| 294 | + assert_equal [c3,c2,c1], assigns(:results) | |
| 295 | + end | |
| 296 | + | |
| 297 | + should 'paginate search of contents in groups of 27' do | |
| 298 | + 1.upto(30).map do |n| | |
| 299 | + create(TinyMceArticle, :name => "Testing article #{n}", :body => "Article body #{n}", :profile => profile) | |
| 300 | + end | |
| 301 | + | |
| 302 | + get :contents | |
| 303 | + assert_equal 27 , assigns(:results).count | |
| 304 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
| 305 | + end | |
| 306 | + | |
| 307 | + should 'paginate ferret search of contents in groups of 27' do | |
| 308 | + 1.upto(30).map do |n| | |
| 309 | + create(TinyMceArticle, :name => "Testing article #{n}", :body => "Article body #{n}", :profile => profile) | |
| 310 | + end | |
| 311 | + | |
| 312 | + get :contents, :query => 'Testing' | |
| 313 | + assert_equal 27 , assigns(:results).count | |
| 314 | + assert_tag :a, '', :attributes => {:class => 'next_page'} | |
| 315 | + end | |
| 316 | + | |
| 317 | + should 'list all contents filter by more comments' do | |
| 318 | + article1 = fast_create(TinyMceArticle, :body => '<p>Article to test browse contents', :profile_id => profile.id, :comments_count => 5) | |
| 319 | + article2 = fast_create(TinyMceArticle, :body => '<p>Another article to test browse contents</p>', :profile_id => profile.id, :comments_count => 10) | |
| 320 | + article3 = fast_create(TinyMceArticle, :body => '<p>Another article to test browse contents</p>', :profile_id => profile.id, :comments_count => 1) | |
| 321 | + | |
| 322 | + get :contents, :filter => 'more_comments' | |
| 323 | + assert_equal [article2,article1,article3] , assigns(:results) | |
| 324 | + end | |
| 325 | + | |
| 326 | + should 'list all contents filter by more views' do | |
| 327 | + article1 = fast_create(TinyMceArticle, :body => '<p>Article to test browse contents', :profile_id => profile.id, :hits => 5) | |
| 328 | + article2 = fast_create(TinyMceArticle, :body => '<p>Another article to test browse contents</p>', :profile_id => profile.id, :hits => 10) | |
| 329 | + article3 = fast_create(TinyMceArticle, :body => '<p>Another article to test browse contents</p>', :profile_id => profile.id, :hits => 1) | |
| 330 | + | |
| 331 | + get :contents, :filter => 'more_views' | |
| 332 | + assert_equal [article2,article1,article3], assigns(:results) | |
| 333 | + end | |
| 334 | + | |
| 335 | + should 'have the more_recent filter by default' do | |
| 336 | + get :contents, :filter => 'more_recent' | |
| 337 | + assert_equal 'more_recent' , assigns(:filter) | |
| 338 | + | |
| 339 | + get :contents, :filter => 'more_comments' | |
| 340 | + assert_equal 'more_comments' , assigns(:filter) | |
| 341 | + | |
| 342 | + get :contents, :filter => 'more_views' | |
| 343 | + assert_equal 'more_views' , assigns(:filter) | |
| 344 | + | |
| 345 | + get :contents, :filter => 'more_anything' | |
| 346 | + assert_equal 'more_recent' , assigns(:filter) | |
| 347 | + end | |
| 348 | + | |
| 349 | + should 'the contents filter define the title' do | |
| 350 | + get :contents, :filter => 'more_recent' | |
| 351 | + assert_equal 'More recent contents' , assigns(:title) | |
| 352 | + assert_tag :h1, :content => 'More recent contents' | |
| 353 | + | |
| 354 | + get :contents, :filter => 'more_views' | |
| 355 | + assert_equal 'Most viewed contents' , assigns(:title) | |
| 356 | + assert_tag :h1, :content => 'Most viewed contents' | |
| 357 | + | |
| 358 | + get :contents, :filter => 'more_comments' | |
| 359 | + assert_equal 'Most commented contents' , assigns(:title) | |
| 360 | + assert_tag :h1, :content => 'Most commented contents' | |
| 361 | + | |
| 362 | + get :contents, :filter => 'more_anything' | |
| 363 | + assert_equal 'More recent contents' , assigns(:title) | |
| 364 | + assert_tag :h1, :content => 'More recent contents' | |
| 365 | + end | |
| 366 | + | |
| 367 | + should "only include published contents in more_recent filter" do | |
| 368 | + # assuming that all filters behave the same! | |
| 369 | + article = fast_create(TinyMceArticle, :body => '<p>Article to test browse contents', :profile_id => profile.id, :published => false) | |
| 370 | + get :contents, :filter => 'more_recent' | |
| 371 | + assert_not_includes assigns(:results), article | |
| 372 | + end | |
| 373 | + | |
| 277 | 374 | end | ... | ... |
test/unit/article_test.rb
| ... | ... | @@ -1562,4 +1562,78 @@ class ArticleTest < Test::Unit::TestCase |
| 1562 | 1562 | end |
| 1563 | 1563 | end |
| 1564 | 1564 | |
| 1565 | + should 'find more recent contents' do | |
| 1566 | + Article.delete_all | |
| 1567 | + | |
| 1568 | + c1 = fast_create(TinyMceArticle, :name => 'Testing article 1', :body => 'Article body 1', :profile_id => profile.id, :created_at => DateTime.now - 4) | |
| 1569 | + c2 = fast_create(TinyMceArticle, :name => 'Testing article 2', :body => 'Article body 2', :profile_id => profile.id, :created_at => DateTime.now - 1) | |
| 1570 | + c3 = fast_create(TinyMceArticle, :name => 'Testing article 3', :body => 'Article body 3', :profile_id => profile.id, :created_at => DateTime.now - 3) | |
| 1571 | + | |
| 1572 | + assert_equal [c2,c3,c1] , Article.more_recent | |
| 1573 | + | |
| 1574 | + c4 = fast_create(TinyMceArticle, :name => 'Testing article 4', :body => 'Article body 4', :profile_id => profile.id, :created_at => DateTime.now - 2) | |
| 1575 | + assert_equal [c2,c4,c3,c1] , Article.more_recent | |
| 1576 | + end | |
| 1577 | + | |
| 1578 | + should 'respond to more comments' do | |
| 1579 | + assert_respond_to Article, :more_comments | |
| 1580 | + end | |
| 1581 | + | |
| 1582 | + should 'respond to more views' do | |
| 1583 | + assert_respond_to Article, :more_views | |
| 1584 | + end | |
| 1585 | + | |
| 1586 | + should "return the more recent label" do | |
| 1587 | + a = Article.new | |
| 1588 | + assert_equal "Created at: ", a.more_recent_label | |
| 1589 | + end | |
| 1590 | + | |
| 1591 | + should "return no comments if profile has 0 comments" do | |
| 1592 | + a = Article.new | |
| 1593 | + assert_equal 0, a.comments_count | |
| 1594 | + assert_equal "no comments", a.more_comments_label | |
| 1595 | + end | |
| 1596 | + | |
| 1597 | + should "return 1 comment on label if the content has 1 comment" do | |
| 1598 | + a = Article.new(:comments_count => 1) | |
| 1599 | + assert_equal 1, a.comments_count | |
| 1600 | + assert_equal "one comment", a.more_comments_label | |
| 1601 | + end | |
| 1602 | + | |
| 1603 | + should "return number of comments on label if the content has more than one comment" do | |
| 1604 | + a = Article.new(:comments_count => 4) | |
| 1605 | + assert_equal 4, a.comments_count | |
| 1606 | + assert_equal "4 comments", a.more_comments_label | |
| 1607 | + end | |
| 1608 | + | |
| 1609 | + should "return no views if profile has 0 views" do | |
| 1610 | + a = Article.new | |
| 1611 | + assert_equal 0, a.hits | |
| 1612 | + assert_equal "no views", a.more_views_label | |
| 1613 | + end | |
| 1614 | + | |
| 1615 | + should "return 1 view on label if the content has 1 view" do | |
| 1616 | + a = Article.new(:hits => 1) | |
| 1617 | + assert_equal 1, a.hits | |
| 1618 | + assert_equal "one view", a.more_views_label | |
| 1619 | + end | |
| 1620 | + | |
| 1621 | + should "return number of views on label if the content has more than one view" do | |
| 1622 | + a = Article.new(:hits => 4) | |
| 1623 | + assert_equal 4, a.hits | |
| 1624 | + assert_equal "4 views", a.more_views_label | |
| 1625 | + end | |
| 1626 | + | |
| 1627 | + should 'return only text articles' do | |
| 1628 | + Article.delete_all | |
| 1629 | + | |
| 1630 | + c1 = fast_create(TinyMceArticle, :name => 'Testing article 1', :body => 'Article body 1', :profile_id => profile.id) | |
| 1631 | + c2 = fast_create(TextArticle, :name => 'Testing article 2', :body => 'Article body 2', :profile_id => profile.id) | |
| 1632 | + c3 = fast_create(Event, :name => 'Testing article 3', :body => 'Article body 3', :profile_id => profile.id) | |
| 1633 | + c4 = fast_create(RssFeed, :name => 'Testing article 4', :body => 'Article body 4', :profile_id => profile.id) | |
| 1634 | + c5 = fast_create(TextileArticle, :name => 'Testing article 5', :body => 'Article body 5', :profile_id => profile.id) | |
| 1635 | + | |
| 1636 | + assert_equal [c1,c2,c5], Article.text_articles | |
| 1637 | + end | |
| 1638 | + | |
| 1565 | 1639 | end | ... | ... |