diff --git a/app/controllers/public/browse_controller.rb b/app/controllers/public/browse_controller.rb new file mode 100644 index 0000000..243b963 --- /dev/null +++ b/app/controllers/public/browse_controller.rb @@ -0,0 +1,58 @@ +class BrowseController < PublicController + + no_design_blocks + + FILTERS = %w( + more_recent + more_active + more_popular + ) + + def people + @filter = filter + @title = self.filter_description(params[:action] + '_' + @filter ) + + @results = @environment.people.send(@filter) + + if params[:query].blank? + @results = @results.paginate(:per_page => 27, :page => params[:page]) + else + @results = @results.find_by_contents(params[:query]).paginate(:per_page => 27, :page => params[:page]) + end + end + + def communities + @filter = filter + @title = self.filter_description(params[:action] + '_' + @filter ) + + @results = @environment.communities.send(@filter) + + if params[:query].blank? + @results = @results.paginate(:per_page => 27, :page => params[:page]) + else + @results = @results.find_by_contents(params[:query]).paginate(:per_page => 27, :page => params[:page]) + end + end + + protected + + def filter + if FILTERS.include?(params[:filter]) + params[:filter] + else + 'more_recent' + end + end + + def filter_description(str) + { + 'people_more_recent' => _('People more recent'), + 'people_more_active' => _('People more active'), + 'people_more_popular' => _('People more popular'), + 'communities_more_recent' => _('Communities more recent'), + 'communities_more_active' => _('Communities more active'), + 'communities_more_popular' => _('Communities more popular'), + }[str] || str + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 178d598..c3d2749 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -479,9 +479,38 @@ module ApplicationHelper :class => the_class end + def links_for_balloon(profile) + if environment.enabled?(:show_balloon_with_profile_links_when_clicked) + if profile.kind_of?(Person) + [ + {_('Home Page') => url_for(profile.url)}, + {_('Profile') => url_for(profile.public_profile_url)}, + {_('Friends') => url_for(:controller => :profile, :action => :friends, :profile => profile.identifier)}, + {_('Communities') => url_for(:controller => :profile, :action => :communities, :profile => profile.identifier)} + ] + elsif profile.kind_of?(Community) + [ + {_('Home Page') => url_for(profile.url)}, + {_('Profile') => url_for(profile.public_profile_url)}, + {_('Members') => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}, + {_('Agenda') => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)} + ] + elsif profile.kind_of?(Enterprise) + [ + {_('Home Page') => url_for(profile.url)}, + {_('Products') => catalog_path(profile.identifier)}, + {_('Members') => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}, + {_('Agenda') => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)} + ] + else + [] + end + end + end + # displays a link to the profile homepage with its image (as generated by # #profile_image) and its name below it. - def profile_image_link( profile, size=:portrait, tag='li' ) + def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil ) if profile.class == Person name = profile.short_name city = content_tag 'span', content_tag( 'span', profile.city, :class => 'locality' ), :class => 'adr' @@ -489,11 +518,14 @@ module ApplicationHelper name = profile.short_name city = '' end + extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) + links = links_for_balloon(profile) content_tag tag, + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => 'menu-submenu-trigger' ) : "") + link_to( content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + - city + profile_sex_icon( profile ) + profile_cat_icons( profile ), + city + extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ), profile.url, :onclick => 'document.location.href = this.href', # work-arround for ie. :class => 'profile_link url', @@ -1019,4 +1051,34 @@ module ApplicationHelper ") : '') end + def browse_people_menu + links = [ + {_('More Recent') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_recent'})}, + {_('More Active') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_active'})}, + {_('More Popular') => url_for({:controller => 'browse', :action => 'people', :filter => 'more_popular'})} + ] + if logged_in? + links.push(_('My friends') => url_for({:profile => current_user.login, :controller => 'friends'})) + links.push(_('Invite friends') => url_for({:profile => current_user.login, :controller => 'invite', :action => 'friends'})) + end + + link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "browse", :action => 'people'}, :id => 'submenu-people') + + link_to(content_tag(:span, _('People Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json})", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger') + end + + def browse_communities_menu + links = [ + {_('More Recent') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_recent'})}, + {_('More Active') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_active'})}, + {_('More Popular') => url_for({:controller => 'browse', :action => 'communities', :filter => 'more_popular'})} + ] + if logged_in? + links.push(_('My communities') => url_for({:profile => current_user.login, :controller => 'memberships'})) + links.push(_('New community') => url_for({:profile => current_user.login, :controller => 'memberships', :action => 'new_community'})) + end + + link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "browse", :action => 'communities'}, :id => 'submenu-communities') + + link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json})", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') + end + end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 1d01020..60dcef7 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -4,7 +4,7 @@ class Enterprise < Organization N_('Enterprise') - has_many :products, :dependent => :destroy + has_many :products, :dependent => :destroy, :order => 'name ASC' extra_data_for_index :product_categories diff --git a/app/models/environment.rb b/app/models/environment.rb index f3e7470..27ef603 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -108,6 +108,7 @@ class Environment < ActiveRecord::Base 'enable_organization_url_change' => _("Allow organizations to change their URL"), 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), + 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), } end diff --git a/app/models/person.rb b/app/models/person.rb index 6393f19..b6b487d 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -8,6 +8,12 @@ class Person < Profile has_many :requested_tasks, :class_name => 'Task', :foreign_key => :requestor_id, :dependent => :destroy + named_scope :more_popular, + :select => "#{Profile.qualified_column_names}, count(friend_id) as total", + :group => Profile.qualified_column_names, + :joins => :friendships, + :order => "total DESC" + after_destroy do |person| Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } end @@ -286,4 +292,13 @@ class Person < Profile def relationships_cache_key cache_key + '-profile-relationships' end + + def more_popular_label + amount = self.friends.count + { + 0 => _('none'), + 1 => _('one friend') + }[amount] || _("%s friends") % amount + end + end diff --git a/app/models/profile.rb b/app/models/profile.rb index b7b39b7..dca5508 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -57,7 +57,23 @@ class Profile < ActiveRecord::Base acts_as_taggable + def self.qualified_column_names + Profile.column_names.map{|n| [Profile.table_name, n].join('.')}.join(',') + end + named_scope :visible, :conditions => { :visible => true } + named_scope :more_recent, :order => "created_at DESC" + named_scope :more_popular, + :select => "#{Profile.qualified_column_names}, count(resource_id) as total", + :group => Profile.qualified_column_names, + :joins => :role_assignments, + :order => "total DESC" + named_scope :more_active, + :select => "#{Profile.qualified_column_names}, count(articles.id) as total, sum(articles.comments_count) as total_comments", + :joins => :articles, + :group => Profile.qualified_column_names, + :order => "total DESC, total_comments DESC", + :conditions => ["articles.created_at BETWEEN ? AND ?", 7.days.ago, DateTime.now] # FIXME ugly workaround def self.human_attribute_name(attrib) @@ -675,6 +691,26 @@ private :generate_url, :url_options cache_key + '-members-page-' + page end + def more_recent_label + _("Since: ") + end + + def more_active_label + amount = self.articles.count + { + 0 => _('none'), + 1 => _('one article') + }[amount] || _("%s articles") % amount + end + + def more_popular_label + amount = self.members.count + { + 0 => _('none'), + 1 => _('one member') + }[amount] || _("%s members") % amount + end + protected def display_private_info_to?(user) @@ -684,4 +720,5 @@ private :generate_url, :url_options (user == self) || (user.is_admin?(self.environment)) || user.is_admin?(self) || user.memberships.include?(self) end end + end diff --git a/app/views/browse/_display_results.rhtml b/app/views/browse/_display_results.rhtml new file mode 100644 index 0000000..8185bb6 --- /dev/null +++ b/app/views/browse/_display_results.rhtml @@ -0,0 +1,19 @@ +
+ +
+ <% if @results.empty? %> +
+
<%= _('None') %>
+
+ <% end %> + +
+
+ +
+
+ diff --git a/app/views/browse/_profile.rhtml b/app/views/browse/_profile.rhtml new file mode 100644 index 0000000..10da93c --- /dev/null +++ b/app/views/browse/_profile.rhtml @@ -0,0 +1 @@ +<%= profile_image_link profile, :portrait, 'li', @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> diff --git a/app/views/browse/_search_form.rhtml b/app/views/browse/_search_form.rhtml new file mode 100644 index 0000000..841f1ff --- /dev/null +++ b/app/views/browse/_search_form.rhtml @@ -0,0 +1,10 @@ +<% form_tag( { :controller => 'browse', :action => action}, :method => 'get', :class => 'search_form' ) do %> + +
+ + <%= text_field_tag 'query', @query, :size => 50 %> + + <%= submit_button(:search, _('Search')) %> +
+ +<% end %> diff --git a/app/views/browse/communities.rhtml b/app/views/browse/communities.rhtml new file mode 100644 index 0000000..411774d --- /dev/null +++ b/app/views/browse/communities.rhtml @@ -0,0 +1,9 @@ +<%= search_page_title( @title, { :query => @query} ) %> + +<%= render :partial => 'search_form', :locals => {:action => 'communities'} %> + +<%= render :partial => 'display_results' %> + +<%= will_paginate @results %> + +
diff --git a/app/views/browse/people.rhtml b/app/views/browse/people.rhtml new file mode 100644 index 0000000..8610c0d --- /dev/null +++ b/app/views/browse/people.rhtml @@ -0,0 +1,9 @@ +<%= search_page_title( @title, { :query => @query} ) %> + +<%= render :partial => 'search_form', :locals => {:action => 'people'} %> + +<%= render :partial => 'display_results' %> + +<%= will_paginate @results %> + +
diff --git a/config/routes.rb b/config/routes.rb index 52f404f..dc62086 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -51,6 +51,10 @@ ActionController::Routing::Routes.draw do |map| # search map.connect 'search/:action/*category_path', :controller => 'search' + # Browse + map.connect 'browse/:action/:filter', :controller => 'browse' + map.connect 'browse/:action', :controller => 'browse' + # events map.events 'profile/:profile/events_by_day', :controller => 'events', :action => 'events_by_day', :profile => /#{Noosfero.identifier_format}/ map.events 'profile/:profile/events/:year/:month/:day', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :day => /\d*/, :profile => /#{Noosfero.identifier_format}/ diff --git a/features/balloon.feature b/features/balloon.feature new file mode 100644 index 0000000..35f2158 --- /dev/null +++ b/features/balloon.feature @@ -0,0 +1,62 @@ +Feature: balloon + I want to view a balloon when mouse clicks on profile trigger + + Background: + Given I am on the homepage + Given the following users + | login | name | + | joaosilva | Joao Silva | + And the following communities + | identifier | name | + | sample | Sample | + + @selenium + Scenario: I should not see trigger if not enabled + Given the following blocks + | owner | type | + | environment | PeopleBlock | + And feature "show_balloon_with_profile_links_when_clicked" is disabled on environment + And I go to the homepage + Then I should not see "Friends" + + @selenium + Scenario: I should not see trigger by default + Given the following blocks + | owner | type | + | environment | PeopleBlock | + And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment + And I go to the homepage + Then I should not see "Friends" + + @selenium + Scenario: I should see balloon when clicked on block trigger + Given the following blocks + | owner | type | + | environment | PeopleBlock | + And feature "show_balloon_with_profile_links_when_clicked" is enabled on environment + And I go to the homepage + When I click ".menu-submenu-trigger" + Then I should see "Profile" + And I should see "Friends" + And I should see "Home Page" + + @selenium + Scenario: I should not see trigger if not enabled on page + Given feature "show_balloon_with_profile_links_when_clicked" is disabled on environment + And I go to /assets/communities + Then I should not see "Members" + + @selenium + Scenario: I should not see trigger by default on page + Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment + And I go to /assets/communities + Then I should not see "Members" + + @selenium + Scenario: I should see balloon when clicked on page trigger + Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment + And I go to /assets/communities + When I click ".menu-submenu-trigger" + Then I should see "Members" + And I should see "Agenda" + And I should see "Home Page" diff --git a/features/browse.feature b/features/browse.feature new file mode 100644 index 0000000..672f324 --- /dev/null +++ b/features/browse.feature @@ -0,0 +1,89 @@ +Feature: browse + As a noosfero visitor + I want to browse people and communities + + Background: + Given I am on the homepage + And the following users + | login | name | + | joaosilva | Joao Silva | + | pedrosilva | Pedro Silva | + | pauloneto | Paulo Neto | + And the following communities + | identifier | name | + | comunity-silva | Community Silva | + | comunity-neto | Community Neto | + + @selenium + Scenario: Show people browse menu + Given I should not see "More Recent" + And I should not see "More Active" + And I should not see "More Popular" + When I click "#submenu-people-trigger" + Then I should see "More Recent" + And I should see "More Active" + And I should see "More Popular" + + @selenium + Scenario: People browse menu should add logged information + Given I am logged in as "joaosilva" + And I should not see "More Recent" + And I should not see "More Active" + And I should not see "More Popular" + And I should not see "Invite friends" + And I should not see "My friends" + When I click "#submenu-people-trigger" + Then I should see "More Recent" + And I should see "More Active" + And I should see "More Popular" + And I should see "Invite friends" + And I should see "My friends" + + @selenium + Scenario: Browse people by query + Given I go to /browse/people + When I fill in "query" with "Silva" + And I press "Search" + Then I should see "Joao Silva" + And I should see "Pedro Silva" + And I should not see "Paulo Neto" + And I should not see "Community Silva" + And I should not see "Community Neto" + + @selenium + Scenario: Communities browse menu should add logged information + Given I am logged in as "joaosilva" + And I am on the homepage + And I should not see "More Recent" + And I should not see "More Active" + And I should not see "More Popular" + And I should not see "My communities" + And I should not see "New community" + When I click "#submenu-communities-trigger" + Then I should see "More Recent" + And I should see "More Active" + And I should see "More Popular" + And I should see "My communities" + And I should see "New community" + + @selenium + Scenario: Show communities browse menu + Given I should not see "More Recent" + And I should not see "More Active" + And I should not see "More Popular" + When I click "#submenu-communities-trigger" + Then I should see "More Recent" + And I should see "More Active" + And I should see "More Popular" + + @selenium + Scenario: Browse communities by query + Given I go to /browse/communities + When I fill in "query" with "Silva" + And I press "Search" + Then I should see "Community Silva" + And I should not see "Joao Silva" + And I should not see "Pedro Silva" + And I should not see "Paulo Neto" + And I should not see "Community Neto" + diff --git a/features/manage_products.feature b/features/manage_products.feature index e99173b..a0b61a4 100644 --- a/features/manage_products.feature +++ b/features/manage_products.feature @@ -17,31 +17,31 @@ Feature: manage products | Bicycle | And the following products | owner | category | name | description | - | redemoinho | bicycle | Bike 1 | bicycle 1 | - | redemoinho | bicycle | Bike 2 | bicycle 2 | - | redemoinho | bicycle | Bike 3 | bicycle 3 | - | redemoinho | bicycle | Bike 4 | bicycle 4 | - | redemoinho | bicycle | Bike 5 | bicycle 5 | - | redemoinho | bicycle | Bike 6 | bicycle 6 | - | redemoinho | bicycle | Bike 7 | bicycle 7 | - | redemoinho | bicycle | Bike 8 | bicycle 8 | - | redemoinho | bicycle | Bike 9 | bicycle 9 | - | redemoinho | bicycle | Bike 10| bicycle 10 | - | redemoinho | bicycle | Bike 11| bicycle 11 | + | redemoinho | bicycle | Bike A | bicycle 1 | + | redemoinho | bicycle | Bike B | bicycle 2 | + | redemoinho | bicycle | Bike C | bicycle 3 | + | redemoinho | bicycle | Bike D | bicycle 4 | + | redemoinho | bicycle | Bike E | bicycle 5 | + | redemoinho | bicycle | Bike F | bicycle 6 | + | redemoinho | bicycle | Bike G | bicycle 7 | + | redemoinho | bicycle | Bike H | bicycle 8 | + | redemoinho | bicycle | Bike I | bicycle 9 | + | redemoinho | bicycle | Bike J | bicycle 10 | + | redemoinho | bicycle | Bike K | bicycle 11 | When I go to /catalog/redemoinho - Then I should see "Bike 1" - And I should see "Bike 2" - And I should see "Bike 3" - And I should see "Bike 4" - And I should see "Bike 5" - And I should see "Bike 6" - And I should see "Bike 7" - And I should see "Bike 8" - And I should see "Bike 9" - And I should see "Bike 10" - And I should not see "Bike 11" + Then I should see "Bike A" within "#product_list" + And I should see "Bike B" within "#product_list" + And I should see "Bike C" within "#product_list" + And I should see "Bike D" within "#product_list" + And I should see "Bike E" within "#product_list" + And I should see "Bike F" within "#product_list" + And I should see "Bike G" within "#product_list" + And I should see "Bike H" within "#product_list" + And I should see "Bike I" within "#product_list" + And I should see "Bike J" within "#product_list" + And I should not see "Bike K" within "#product_list" When I follow "Next" - Then I should see "Bike 11" + Then I should see "Bike K" within "#product_list" Scenario: listing products and services Given I am logged in as "joaosilva" diff --git a/public/designs/themes/base/navigation.rhtml b/public/designs/themes/base/navigation.rhtml index 5946359..1dd46c6 100644 --- a/public/designs/themes/base/navigation.rhtml +++ b/public/designs/themes/base/navigation.rhtml @@ -1,5 +1,7 @@ -
  • <%= _('People') %>
  • -
  • <%= _('Communities') %>
  • -
  • <%= _('Enterprises') %>
  • -
  • <%= _('Products') %>
  • +
  • + <%= browse_people_menu %> +
  • +
  • + <%= browse_communities_menu %> +
  • <%= _('Events') %>
  • diff --git a/public/designs/themes/base/style.css b/public/designs/themes/base/style.css index 83da3c3..589e689 100644 --- a/public/designs/themes/base/style.css +++ b/public/designs/themes/base/style.css @@ -201,18 +201,20 @@ body, th, td, input { margin: 0px; padding: 0px 10px 0px 0px; float: right; - overflow: hidden; } #navigation li { list-style: none; display: block; - height: 54px; + height: auto; + width: 125px; float: left; - border-left: 1px solid #888a85; + text-align: center; + position: relative; } #navigation a { + border-left: 1px solid #888a85; display: block; font-size: 15px; line-height: 42px; @@ -225,11 +227,71 @@ body, th, td, input { } #navigation span { - padding: 0px 10px 0px 35px; - background-position: 15px 50%; + padding: 0px 0px 0px 30px; + background-position: 5px 50%; background-repeat: no-repeat; } +#navigation .menu-submenu ul, #navigation .menu-submenu li{ + float: none; + text-align: right; + border-left: 0px; +} + +#navigation .menu-submenu ul{ + border: 1px solid #888a85; + border-top: 0px; + border-left: 0px; + background-color: #ccc; + padding-right: 2px; + height: auto; + display: block; +} + +#navigation .menu-submenu{ + bottom: -75px; + width: 126px; + top: 0px; + right: 0px; + position: relative; +} + +#navigation .menu-submenu a{ + padding: 4px 5px; + font-size: 12px; + line-height: normal; +} + +#navigation .menu-submenu-trigger { + background: #eee url(/images/down-arrow.png) center center no-repeat; + border: 0px; + height: 8px; + width: 124px; +} +#navigation li:hover .menu-submenu-trigger:hover { + background: #eee url(/images/down-arrow.png) center center no-repeat; +} + +#navigation li:hover .menu-submenu-trigger{ + display: block; +} + +#navigation li .menu-submenu-trigger{ + display: none; +} + +#navigation .menu-submenu-header, #navigation .menu-submenu-footer, #navigation .menu-submenu h4{ + display: none; +} + +#navigation .common-profile-list-block .vcard .menu-submenu-trigger, +.menu-submenu-trigger { + left: 1px; + top: 33px; + -moz-border-radius: 0px; + -webkit-border-radius: 0px; +} + /***************************** boxes ********************************/ .template-default .box-1 { /* Center */ @@ -1119,12 +1181,12 @@ hr.pre-posts, hr.sep-posts { /******** controller-friends action-friends-index ********/ .action-friends-index .profile-list li, -.common-profile-list-block .vcard a { +.common-profile-list-block .vcard { border: 1px solid transparent; } .action-friends-index .profile-list li:hover, -.common-profile-list-block .vcard a:hover { +.common-profile-list-block .vcard:hover { border: 1px solid #CCC; -moz-border-radius: 5px; -webkit-border-radius: 5px; @@ -1132,6 +1194,11 @@ hr.pre-posts, hr.sep-posts { text-decoration: none; } +.common-profile-list-block .vcard a, +.common-profile-list-block .vcard a:hover { + background: transparent; + border: 0; +} /******** controller-profile action-profile-index ********/ @@ -1205,4 +1272,56 @@ table.profile th { border-bottom: 2px solid black; } +/**************************** Browse *******************************/ +.controller-browse #content .search_form { + background: #DDD; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + padding: 12px 15px 13px 15px; + position: relative; + text-align: left; +} + +.controller-browse a { + color: #555753; +} + +.browse-results-innerbox { + margin-top: 10px; + border-bottom: none; + border: 1px solid #CCC; + background: url(imgs/comment-bg-S.png) 0% 100% repeat-x; + padding-bottom: 10px; + +} +.browse-results-innerbox ul{ + padding: 0px; +} + +.browse-results-innerbox .browse-results-type-empty div { + text-align: center; + color: #DDD; + font-weight: bold; + font-size: 30px; + padding: 70px 10px 0px 0px; + border: none; + +} + +.search-results-type-article.search-results-innerbox { + padding: 5px 0px 5px 10px; + max-height: 215px; + height: 225px; +} + +#content .search-results-type-article li { + padding: 5px 0px; +} + +.search-results-type-article a { + text-decoration: none; +} +.search-results-type-article a:hover { + text-decoration: underline; +} diff --git a/public/images/balloon-footer.png b/public/images/balloon-footer.png new file mode 100644 index 0000000..3c1a606 Binary files /dev/null and b/public/images/balloon-footer.png differ diff --git a/public/images/balloon-header.png b/public/images/balloon-header.png new file mode 100644 index 0000000..054e5d3 Binary files /dev/null and b/public/images/balloon-header.png differ diff --git a/public/images/balloon-middle.png b/public/images/balloon-middle.png new file mode 100644 index 0000000..83cee0e Binary files /dev/null and b/public/images/balloon-middle.png differ diff --git a/public/images/down-arrow.png b/public/images/down-arrow.png new file mode 100644 index 0000000..9e6b5dc Binary files /dev/null and b/public/images/down-arrow.png differ diff --git a/public/images/top-arrow.png b/public/images/top-arrow.png new file mode 100644 index 0000000..9b2b158 Binary files /dev/null and b/public/images/top-arrow.png differ diff --git a/public/javascripts/application.js b/public/javascripts/application.js index afb769c..3c5b4a2 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -214,3 +214,52 @@ function expandCategory(block, id) { } } } + +function toggleSubmenu(trigger, title, link_list) { + trigger.onclick = function() { + var submenu = jQuery(trigger).siblings('.menu-submenu'); + var hide = false; + if (submenu.length > 0 && submenu.is(':visible')) hide = true; + hideAllSubmenus(); + // Hide or show this submenu if it already exists + if (submenu.length > 0) { + if (!hide) { + var direction = 'down'; + if (submenu.hasClass('up')) direction = 'up'; + submenu.show('slide', { 'direction' : direction }, 'slow'); + } + } + return false; + } + + hideAllSubmenus(); + // Build and show this submenu if it doesn't exist yet + var direction = 'down'; + if (jQuery(trigger).hasClass('up')) direction = 'up'; + var submenu = jQuery('
    ').attr('class', 'menu-submenu ' + direction).attr('style', 'display: none'); + var header = jQuery('
    ').attr('class', 'menu-submenu-header'); + var content = jQuery('
    ').attr('class', 'menu-submenu-content'); + var list = jQuery('').attr('class', 'menu-submenu-list'); + var footer = jQuery('
    ').attr('class', 'menu-submenu-footer'); + content.append('

    ' + title + '

    '); + jQuery.each(link_list, function(index, link_hash) { + for (label in link_hash) { + list.append('
  • ' + label + '
  • '); + } + }); + content.append(list); + submenu.append(header).append(content).append(footer); + jQuery(trigger).before(submenu); + submenu.show('slide', { 'direction' : direction }, 'slow'); +} + +function hideAllSubmenus() { + jQuery('.menu-submenu.up:visible').hide('slide', { 'direction' : 'up' }, 'slow'); + jQuery('.menu-submenu.down:visible').hide('slide', { 'direction' : 'down' }, 'slow'); +} + +// Hide visible ballons when clicked outside them +jQuery(document).ready(function() { + jQuery('body').click(function() { hideAllSubmenus(); }); + jQuery('.menu-submenu-trigger').click(function(e) { e.stopPropagation(); }); +}); diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 6f128e8..fc2db10 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -1644,13 +1644,13 @@ input.disabled { margin: 0px; padding: 0px; list-style: none; - display: inline; + position: relative; } .common-profile-list-block .vcard a { display: block; - height: 95px; - max-height: 92px; + height: 112px; + max-height: 112px; padding-top: 3px; margin: 0px 2px; float: left; @@ -1738,6 +1738,12 @@ input.disabled { display: none; } +.common-profile-list-block .extra_info { + font-size: 9px; + opacity: 0.5; + filter: alpha(opacity=50); +} + /* ==> blocks/recent-documents-block.css <<= */ @@ -3603,7 +3609,6 @@ h1#agenda-title { border: 1px solid #2A5896; padding: 10px 0px 10px 10px; height: 205px; - overflow: auto; position: relative; /* work-arround-bug fo MSIE */ } @@ -3630,6 +3635,7 @@ h1#agenda-title { .controller-search .only-one-result-box .search-results-innerbox, .controller-search .only-one-result-box .search-results-innerbox.common-profile-list-block { height: auto; + float: left; padding: 10px 4px 10px 10px; } @@ -4088,3 +4094,100 @@ h1#agenda-title { .categories-block .ui-icon { margin-top: 2px; } + +/* Profile balloon */ + +.common-profile-list-block .vcard { + position: relative !important; + float: left; +} + +.common-profile-list-block .vcard .menu-submenu-trigger, +.menu-submenu-trigger { + display: none; + width: 16px; + height: 16px; + position: absolute; + top: -1px; + left: -3px; + overflow: hidden; + background: #efefef url(/images/top-arrow.png) center center no-repeat; + border: 1px solid #ccc; + z-index: 2; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.common-profile-list-block .vcard .menu-submenu-trigger:hover, +.menu-submenu-trigger:hover { + background: #fff url(/images/top-arrow.png) center center no-repeat; + border: 1px solid #ccc; +} + +.menu-submenu-trigger span { + display: none; +} + +.common-profile-list-block .vcard:hover .menu-submenu-trigger { + display: block; +} + +.menu-submenu { + position: absolute; + bottom: 115px; + right: -27px; + z-index: 11; + width: 150px; + padding: 0; + text-align: left; +} + +.menu-submenu-footer { + background: transparent url(/images/balloon-footer.png) center center no-repeat; + height: 29px; + margin: 0; +} + +.menu-submenu-header { + background: transparent url(/images/balloon-header.png) center center no-repeat; + height: 17px; + margin: 0; +} + +.menu-submenu-content { + background: transparent url(/images/balloon-middle.png) top left repeat-y; + margin: 0; + padding: 0; + width: 100%; +} + +#content .menu-submenu-content ul { + margin: 0; + padding: 0; + width: 100% !important; + min-width: 100% !important; +} + +#content .menu-submenu-content ul a { + text-align: left; + padding-left: 12px; +} + +.common-profile-list-block .vcard .menu-submenu a { + float: none; + display: block; + height: auto; + font-size: 12px; +} + +#content .menu-submenu h4 { + margin: 0; + font-size: 12px; + font-weight: bold; + text-align: left; + margin: 0 auto; + padding-bottom: 3px; + margin-bottom: 3px; + border-bottom: 1px solid #000; + width: 90%; +} diff --git a/test/functional/browse_controller_test.rb b/test/functional/browse_controller_test.rb new file mode 100644 index 0000000..969faec --- /dev/null +++ b/test/functional/browse_controller_test.rb @@ -0,0 +1,221 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'browse_controller' + +# Re-raise errors caught by the controller. +class BrowseController; def rescue_action(e) raise e end; end + +class BrowseControllerTest < Test::Unit::TestCase + + def setup + @controller = BrowseController.new + @request = ActionController::TestRequest.new + @request.stubs(:ssl?).returns(false) + @response = ActionController::TestResponse.new + + # By pass user validation on person creation + user = mock() + user.stubs(:id).returns(1) + user.stubs(:valid?).returns(true) + user.stubs(:email).returns('some@test.com') + user.stubs(:save!).returns(true) + Person.any_instance.stubs(:user).returns(user) + end + + should 'search for people' do + Person.delete_all + small = create(Person, :name => 'A small person for testing', :user_id => 1) + create(Person, :name => 'A big person for testing', :user_id => 2) + + get :people, :query => 'small' + assert_equal [small], assigns(:results) + end + + should 'list all people order by more recent one by default' do + Person.delete_all + p1 = create(Person, :name => 'Testing person 1', :user_id => 1, :created_at => DateTime.now - 2) + p2 = create(Person, :name => 'Testing person 2', :user_id => 2, :created_at => DateTime.now - 1) + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) + + get :people + assert_equal [p3,p2,p1] , assigns(:results) + end + + should 'paginate search of people in groups of 27' do + Person.delete_all + + 1.upto(30).map do |n| + create(Person, :name => 'Testing person', :user_id => n) + end + + get :people + assert_equal 30 , Person.count + assert_equal 27 , assigns(:results).count + assert_tag :a, '', :attributes => {:class => 'next_page'} + end + + should 'paginate ferret search of people in groups of 27' do + Person.delete_all + + 1.upto(30).map do |n| + create(Person, :name => 'Testing person', :user_id => n) + end + + get :people, :query => 'Testing' + assert_equal 27 , assigns(:results).count + assert_tag :a, '', :attributes => {:class => 'next_page'} + end + + should 'list all people filter by more active' do + Person.delete_all + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) + Article.delete_all + fast_create(Article, :profile_id => p1, :created_at => 1.day.ago) + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) + get :people, :filter => 'more_active' + assert_equal [p1,p2] , assigns(:results) + end + + should 'filter more popular people' do + Person.delete_all + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) + p3 = create(Person, :name => 'Testing person 3', :user_id => 3) + + p1.add_friend(p2) + p2.add_friend(p1) + p2.add_friend(p3) + get :people, :filter => 'more_popular' + assert_equal [p2,p1] , assigns(:results) + end + + should 'the people filter be only the hardcoded one' do + get :people, :filter => 'more_recent' + assert_equal 'more_recent' , assigns(:filter) + + get :people, :filter => 'more_active' + assert_equal 'more_active' , assigns(:filter) + + get :people, :filter => 'more_popular' + assert_equal 'more_popular' , assigns(:filter) + + get :people, :filter => 'more_anything' + assert_equal 'more_recent' , assigns(:filter) + end + + should 'the people filter define the title' do + get :people, :filter => 'more_recent' + assert_equal 'People more recent' , assigns(:title) + assert_tag :h1, :content => 'People more recent' + + get :people, :filter => 'more_active' + assert_equal 'People more active' , assigns(:title) + assert_tag :h1, :content => 'People more active' + + get :people, :filter => 'more_popular' + assert_equal 'People more popular' , assigns(:title) + assert_tag :h1, :content => 'People more popular' + + get :people, :filter => 'more_anything' + assert_equal 'People more recent' , assigns(:title) + assert_tag :h1, :content => 'People more recent' + end + + should 'search for community' do + small = create(Community, :name => 'A small community for testing') + create(Community, :name => 'A big community for testing') + + get :communities, :query => 'small' + assert_equal [small], assigns(:results) + end + + should 'list all community order by more recent one by default' do + c1 = create(Community, :name => 'Testing community 1', :created_at => DateTime.now - 2) + c2 = create(Community, :name => 'Testing community 2', :created_at => DateTime.now - 1) + c3 = create(Community, :name => 'Testing community 3') + + get :communities + assert_equal [c3,c2,c1] , assigns(:results) + end + + should 'paginate search of communities in groups of 27' do + 1.upto(30).map do |n| + create(Community, :name => 'Testing community') + end + + get :communities + assert_equal 30 , Community.count + assert_equal 27 , assigns(:results).count + assert_tag :a, '', :attributes => {:class => 'next_page'} + end + + should 'paginate ferret search of communities in groups of 27' do + 1.upto(30).map do |n| + create(Community, :name => 'Testing community') + end + + get :communities, :query => 'Testing' + assert_equal 27 , assigns(:results).count + assert_tag :a, '', :attributes => {:class => 'next_page'} + end + + should 'list all communities filter by more active' do + c1 = create(Community, :name => 'Testing community 1') + c2 = create(Community, :name => 'Testing community 2') + c3 = create(Community, :name => 'Testing community 3') + Article.delete_all + fast_create(Article, :profile_id => c1, :created_at => 1.day.ago) + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) + get :communities, :filter => 'more_active' + assert_equal [c1,c2] , assigns(:results) + end + + should 'filter more popular communities' do + Person.delete_all + c1 = create(Community, :name => 'Testing community 1') + c2 = create(Community, :name => 'Testing community 2') + create(Community, :name => 'Testing community 3') + + p1 = create(Person, :name => 'Testing person 1', :user_id => 1) + p2 = create(Person, :name => 'Testing person 2', :user_id => 2) + c1.add_member(p1) + c2.add_member(p1) + c2.add_member(p2) + get :communities, :filter => 'more_popular' + assert_equal [c2,c1] , assigns(:results) + end + + should 'the communities filter be only the hardcoded one' do + get :communities, :filter => 'more_recent' + assert_equal 'more_recent' , assigns(:filter) + + get :communities, :filter => 'more_active' + assert_equal 'more_active' , assigns(:filter) + + get :communities, :filter => 'more_popular' + assert_equal 'more_popular' , assigns(:filter) + + get :communities, :filter => 'more_anything' + assert_equal 'more_recent' , assigns(:filter) + end + + should 'the communities filter define the title' do + get :communities, :filter => 'more_recent' + assert_equal 'Communities more recent' , assigns(:title) + assert_tag :h1, :content => 'Communities more recent' + + get :communities, :filter => 'more_active' + assert_equal 'Communities more active' , assigns(:title) + assert_tag :h1, :content => 'Communities more active' + + get :communities, :filter => 'more_popular' + assert_equal 'Communities more popular' , assigns(:title) + assert_tag :h1, :content => 'Communities more popular' + + get :communities, :filter => 'more_anything' + assert_equal 'Communities more recent' , assigns(:title) + assert_tag :h1, :content => 'Communities more recent' + end + +end diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index 3b28a71..e0538ee 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -216,4 +216,11 @@ class RoutingTest < ActionController::IntegrationTest assert_routing('/doc', :controller => 'doc', :action => 'index') end + # browse controller + def test_browse_routing + assert_routing('/browse/people', :controller => 'browse', :action => 'people') + assert_routing('/browse/people/more_popular', :controller => 'browse', :action => 'people', :filter => 'more_popular') + assert_routing('/browse/communities', :controller => 'browse', :action => 'communities') + assert_routing('/browse/communities/more_active', :controller => 'browse', :action => 'communities', :filter => 'more_active') + end end diff --git a/test/unit/application_helper_test.rb b/test/unit/application_helper_test.rb index 186b605..fbc4f80 100644 --- a/test/unit/application_helper_test.rb +++ b/test/unit/application_helper_test.rb @@ -567,6 +567,60 @@ class ApplicationHelperTest < Test::Unit::TestCase assert_equal environment.theme, current_theme end + should 'trunc to 15 chars the big filename' do + assert_equal 'AGENDA(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3',15) + end + + should 'trunc to default limit the big filename' do + assert_equal 'AGENDA_CULTURA_-_FESTA_DE_VAQUEIRO(...).mp3', short_filename('AGENDA_CULTURA_-_FESTA_DE_VAQUEIROS_PONTO_DE_SERRA_PRETA_BAIXA.mp3') + end + + should 'does not trunc short filename' do + assert_equal 'filename.mp3', short_filename('filename.mp3') + end + + should 'return nil when :show_balloon_with_profile_links_when_clicked is not enabled in environment' do + env = Environment.default + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(false) + stubs(:environment).returns(env) + profile = Profile.new + assert_nil links_for_balloon(profile) + end + + should 'return ordered list of links to balloon to Person' do + env = Environment.default + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) + stubs(:environment).returns(env) + person = Person.new + person.stubs(:url).returns('url for person') + person.stubs(:public_profile_url).returns('url for person') + links = links_for_balloon(person) + assert_equal ['Home Page', 'Profile', 'Friends', 'Communities'], links.map{|i| i.keys.first} + end + + should 'return ordered list of links to balloon to Community' do + env = Environment.default + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) + stubs(:environment).returns(env) + community = Community.new + community.stubs(:url).returns('url for community') + community.stubs(:public_profile_url).returns('url for community') + links = links_for_balloon(community) + assert_equal ['Home Page', 'Profile', 'Members', 'Agenda'], links.map{|i| i.keys.first} + end + + should 'return ordered list of links to balloon to Enterprise' do + env = Environment.default + env.stubs(:enabled?).with(:show_balloon_with_profile_links_when_clicked).returns(true) + stubs(:environment).returns(env) + enterprise = Enterprise.new + enterprise.stubs(:url).returns('url for enterprise') + enterprise.stubs(:public_profile_url).returns('url for enterprise') + stubs(:catalog_path) + links = links_for_balloon(enterprise) + assert_equal ['Home Page', 'Products', 'Members', 'Agenda'], links.map{|i| i.keys.first} + end + protected def url_for(args = {}) diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb index 7aebcf3..ffe29c2 100644 --- a/test/unit/person_test.rb +++ b/test/unit/person_test.rb @@ -588,4 +588,51 @@ class PersonTest < Test::Unit::TestCase end end + should "return none on label if the person hasn't friends" do + p = fast_create(Person) + assert_equal 0, p.friends.count + assert_equal "none", p.more_popular_label + end + + should "return one friend on label if the profile has one member" do + p1 = fast_create(Person) + p2 = fast_create(Person) + p1.add_friend(p2) + assert_equal 1, p1.friends.count + assert_equal "one friend", p1.more_popular_label + end + + should "return the number of friends on label if the person has more than one friend" do + p1 = fast_create(Person) + p2 = fast_create(Person) + p3 = fast_create(Person) + p1.add_friend(p2) + p1.add_friend(p3) + assert_equal 2, p1.friends.count + assert_equal "2 friends", p1.more_popular_label + + p4 = fast_create(Person) + p1.add_friend(p4) + assert_equal 3, p1.friends.count + assert_equal "3 friends", p1.more_popular_label + end + + should 'find more popular people' do + Person.delete_all + env = fast_create(Environment) + p1 = fast_create(Person) + p2 = fast_create(Person) + p3 = fast_create(Person) + + p1.add_friend(p2) + assert_equal [p1], Person.more_popular + + p2.add_friend(p1) + p2.add_friend(p3) + assert_equal [p2,p1] , Person.more_popular + + p2.remove_friend(p3) + assert_equal [p1,p2] , Person.more_popular + end + end diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index 30898f2..5ec2e9f 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -1563,6 +1563,212 @@ class ProfileTest < Test::Unit::TestCase assert_match /

    Wellformed html code <\/h1>/, profile.custom_footer end + should 'find more recent people' do + Person.delete_all + p1 = fast_create(Person,:created_at => 4.days.ago) + p2 = fast_create(Person, :created_at => DateTime.now) + p3 = fast_create(Person, :created_at => 2.days.ago) + + assert_equal [p2,p3,p1] , Person.more_recent + + p4 = fast_create(Person, :created_at => 3.days.ago) + assert_equal [p2,p3,p4,p1] , Person.more_recent + end + + should 'find more active people' do + Person.delete_all + p1 = fast_create(Person) + p2 = fast_create(Person) + p3 = fast_create(Person) + Article.delete_all + fast_create(Article, :profile_id => p1, :created_at => 7.days.ago) + fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) + assert_equal [p1,p2] , Person.more_active + + fast_create(Article, :profile_id => p2, :created_at => 1.day.ago) + fast_create(Article, :profile_id => p2, :created_at => 5.days.ago) + fast_create(Article, :profile_id => p3, :created_at => 2.days.ago) + assert_equal [p2,p1,p3] , Person.more_active + end + + should 'the ties on more active people be solved by the number of comments' do + Person.delete_all + p1 = fast_create(Person) + p2 = fast_create(Person) + Article.delete_all + a1 = fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) + a2 = fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) + assert_equal [], [p1,p2] - Person.more_active + assert_equal [], Person.more_active - [p1, p2] + + a2.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! + assert_equal [p2,p1] , Person.more_active + + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p2).save! + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p2).save! + assert_equal [p1,p2] , Person.more_active + end + + should 'more active people take in consideration only articles created current the last week' do + Person.delete_all + env = fast_create(Environment) + p1 = fast_create(Person) + p2 = fast_create(Person) + p3 = fast_create(Person) + Article.delete_all + fast_create(Article, :profile_id => p1, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => p2, :created_at => 10.days.ago) + assert_equal [p1] , Person.more_active + + fast_create(Article, :profile_id => p2, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => p2, :created_at => 7.days.ago) + fast_create(Article, :profile_id => p3, :created_at => 8.days.ago) + assert_equal [p2,p1] , Person.more_active + end + + should 'find more recent community' do + c1 = fast_create(Community, :created_at => 3.days.ago) + c2 = fast_create(Community, :created_at => 1.day.ago) + c3 = fast_create(Community, :created_at => DateTime.now) + + assert_equal [c3,c2,c1] , Community.more_recent + + c4 = fast_create(Community, :created_at => 2.days.ago) + assert_equal [c3,c2,c4,c1] , Community.more_recent + end + + should 'find more active community' do + c1 = fast_create(Community) + c2 = fast_create(Community) + c3 = fast_create(Community) + + Article.delete_all + fast_create(Article, :profile_id => c1, :created_at => 1.day.ago) + fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) + assert_equal [c1,c2], Community.more_active + + fast_create(Article, :profile_id => c2, :created_at => 2.days.ago) + fast_create(Article, :profile_id => c2, :created_at => 7.days.ago) + fast_create(Article, :profile_id => c3, :created_at => 1.day.ago) + assert_equal [c2,c1,c3] , Community.more_active + end + + should 'the ties on more active communities be solved by the number of comments' do + env = create(Environment) + Community.delete_all + c1 = fast_create(Community) + c2 = fast_create(Community) + Article.delete_all + a1 = fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) + a2 = fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) + assert_equal [c1,c2] , Community.more_active + + p1 = fast_create(Person) + a2.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! + assert_equal [c2,c1] , Community.more_active + + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! + a1.comments.build(:title => 'test comment', :body => 'anything', :author => p1).save! + assert_equal [c1,c2] , Community.more_active + end + + should 'more active communities take in consideration only articles created current the last week' do + c1 = fast_create(Community) + c2 = fast_create(Community) + c3 = fast_create(Community) + Article.delete_all + fast_create(Article, :profile_id => c1, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => c2, :created_at => 10.days.ago) + assert_equal [c1] , Community.more_active + + fast_create(Article, :profile_id => c2, :created_at => DateTime.now.beginning_of_day) + fast_create(Article, :profile_id => c2, :created_at => 7.days.ago) + fast_create(Article, :profile_id => c3, :created_at => 8.days.ago) + assert_equal [c2,c1] , Community.more_active + end + + should 'find more popular communities' do + Community.delete_all + + c1 = fast_create(Community) + c2 = fast_create(Community) + fast_create(Community) + + p1 = fast_create(Person) + p2 = fast_create(Person) + c1.add_member(p1) + assert_equal [c1] , Community.more_popular + + c2.add_member(p1) + c2.add_member(p2) + assert_equal [c2,c1] , Community.more_popular + + c2.remove_member(p2) + c2.remove_member(p1) + assert_equal [c1] , Community.more_popular + end + + should "return the more recent label" do + p = fast_create(Profile) + assert_equal "Since: ", p.more_recent_label + end + + should "return none on label if the profile hasn't articles" do + p = fast_create(Profile) + assert_equal 0, p.articles.count + assert_equal "none", p.more_active_label + end + + should "return one article on label if the profile has one article" do + p = fast_create(Profile) + fast_create(Article, :profile_id => p.id) + assert_equal 1, p.articles.count + assert_equal "one article", p.more_active_label + end + + should "return number of artciles on label if the profile has more than one article" do + p = fast_create(Profile) + fast_create(Article, :profile_id => p.id) + fast_create(Article, :profile_id => p.id) + assert_equal 2, p.articles.count + assert_equal "2 articles", p.more_active_label + + fast_create(Article, :profile_id => p.id) + assert_equal 3, p.articles.count + assert_equal "3 articles", p.more_active_label + end + + should "return none on label if the profile hasn't members" do + p = fast_create(Profile) + assert_equal 0, p.members.count + assert_equal "none", p.more_popular_label + end + + should "return one member on label if the profile has one member" do + p = fast_create(Person) + c = fast_create(Community) + c.add_member(p) + assert_equal 1, c.members.count + assert_equal "one member", c.more_popular_label + end + + should "return the number of members on label if the profile has more than one member" do + p1 = fast_create(Profile) + p2 = fast_create(Person) + c = fast_create(Community) + c.add_member(p1) + c.add_member(p2) + assert_equal 2, c.members.count + assert_equal "2 members", c.more_popular_label + + p3 = fast_create(Person) + c.add_member(p3) + assert_equal 3, c.members.count + assert_equal "3 members", c.more_popular_label + end + private def assert_invalid_identifier(id) -- libgit2 0.21.2