diff --git a/plugins/relevant_content/lib/ext/article.rb b/plugins/relevant_content/lib/ext/article.rb new file mode 100644 index 0000000..9a5e3d1 --- /dev/null +++ b/plugins/relevant_content/lib/ext/article.rb @@ -0,0 +1,194 @@ +require_dependency 'article' + +class Article + + named_scope :relevant_content, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'Blog' and articles.type != 'RssFeed') OR articles.type is NULL"] + + def self.most_accessed(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.relevant_content.find( + :all, + :order => 'hits desc', + :limit => limit, + :conditions => ["hits > 0"] + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.relevant_content.find( + :all, + :order => 'hits desc', + :limit => limit, + :conditions => ["profile_id = ? and hits > 0", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.most_commented_relevant_content(owner, limit) + + if owner.kind_of?(Environment) + result = Article.relevant_content.find( + :all, + :order => 'comments_count desc', + :limit => limit, + :conditions => ["comments_count > 0"] + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.relevant_content.find( + :all, + :order => 'comments_count desc', + :limit => limit, + :conditions => ["profile_id = ? and comments_count > 0", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.articles_columns + Article.column_names.map {|c| "articles.#{c}"} .join(",") + end + + def self.more_positive_votes(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.find( + :all, + :select => articles_columns, + :order => 'sum(vote) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :having => ['sum(vote) > 0'], + :conditions => {'votes.voteable_type' => 'Article'}, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id' + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.find( + :all, + :select => articles_columns, + :order => 'sum(vote) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :having => ['sum(vote) > 0'], + :conditions => ["profile_id = ? and votes.voteable_type = ? ", owner.id, 'Article'] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.more_negative_votes(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.find( + :all, + :select => articles_columns, + :order => 'sum(vote) asc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :having => ['sum(vote) < 0'], + :conditions => {'votes.voteable_type' => 'Article'}, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id' + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.find( + :all, + :select => articles_columns, + :order => 'sum(vote) asc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :having => ['sum(vote) < 0'], + :conditions => ["profile_id = ? and votes.voteable_type = 'Article' ", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.most_liked(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article' and vote > 0"] + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article' and vote > 0 and profile_id = ? ", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.most_disliked(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.find( + :all, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article' and vote < 0"] + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.find( + :all, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article' and vote < 0 and profile_id = ? ", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + def self.most_voted(owner, limit = nil) + if owner.kind_of?(Environment) + result = Article.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article'"] + ) + result.paginate({:page => 1, :per_page => limit}) + else + #Owner is a profile + result = Article.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id', + :conditions => ["votes.voteable_type = 'Article' and profile_id = ? ", owner.id] + ) + result.paginate({:page => 1, :per_page => limit}) + end + end + + + + +end \ No newline at end of file diff --git a/plugins/relevant_content/lib/relevant_content_plugin.rb b/plugins/relevant_content/lib/relevant_content_plugin.rb new file mode 100644 index 0000000..012766c --- /dev/null +++ b/plugins/relevant_content/lib/relevant_content_plugin.rb @@ -0,0 +1,21 @@ +class RelevantContentPlugin < Noosfero::Plugin + + def self.plugin_name + "Relevant Content Plugin" + end + + def self.plugin_description + _("A plugin that lists the most accessed, most commented, most liked and most disliked contents.") + end + + def self.extra_blocks + { + RelevantContentPlugin::RelevantContentBlock => {:position => ['1','2','3'] } + } + end + + def stylesheet? + true + end + +end diff --git a/plugins/relevant_content/lib/relevant_content_plugin/relevant_content_block.rb b/plugins/relevant_content/lib/relevant_content_plugin/relevant_content_block.rb new file mode 100644 index 0000000..b076e56 --- /dev/null +++ b/plugins/relevant_content/lib/relevant_content_plugin/relevant_content_block.rb @@ -0,0 +1,93 @@ +class RelevantContentPlugin::RelevantContentBlock < Block + def self.description + _('Relevant content') + end + + def default_title + _('Relevant content') + end + + def help + _('This block lists the most popular content.') + end + + settings_items :limit, :type => :integer, :default => 5 + settings_items :show_most_read, :type => :integer, :default => 1 + settings_items :show_most_commented, :type => :integer, :default => 1 + settings_items :show_most_liked, :type => :integer, :default => 1 + settings_items :show_most_disliked, :type => :integer, :default => 0 + settings_items :show_most_voted, :type => :integer, :default => 1 + + include ActionController::UrlWriter + def content(args={}) + + content = block_title(title) + + if self.show_most_read != 0 + docs = Article.most_accessed(owner, self.limit) + if !docs.blank? + subcontent = "" + subcontent += content_tag(:span, _("Most read articles"), :class=>"title mread") + "\n" + subcontent += content_tag(:ul, docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) + content += content_tag(:div, subcontent, :class=>"block mread") + "\n" + end + end + + if self.show_most_commented != 0 + docs = Article.most_commented_relevant_content(owner, self.limit) + if !docs.blank? + subcontent = "" + subcontent += content_tag(:span, _("Most commented articles"), :class=>"title mcommented") + "\n" + subcontent += content_tag(:ul, docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) + content += content_tag(:div, subcontent, :class=>"block mcommented") + "\n" + end + end + + if owner.kind_of?(Environment) + env = owner + else + env = owner.environment + end + + if env.plugin_enabled?(VotePlugin) + if self.show_most_liked != 0 + docs = Article.more_positive_votes(owner, self.limit) + if !docs.blank? + subcontent = "" + subcontent += content_tag(:span, _("Most liked articles"), :class=>"title mliked") + "\n" + subcontent += content_tag(:ul, docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) + content += content_tag(:div, subcontent, :class=>"block mliked") + "\n" + end + end + if self.show_most_disliked != 0 + docs = Article.more_negative_votes(owner, self.limit) + if !docs.blank? + subcontent = "" + subcontent += content_tag(:span, _("Most disliked articles"), :class=>"title mdisliked") + "\n" + subcontent += content_tag(:ul, docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) + content += content_tag(:div, subcontent, :class=>"block mdisliked") + "\n" + end + end + + if self.show_most_voted != 0 + docs = Article.most_voted(owner, self.limit) + if !docs.blank? + subcontent = "" + subcontent += content_tag(:span, _("Most voted articles"), :class=>"title mvoted") + "\n" + subcontent += content_tag(:ul, docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) + content += content_tag(:div, subcontent, :class=>"block mvoted") + "\n" + end + end + end + return content + end + + def timeout + 4.hours + end + + def self.expire_on + { :profile => [:article], :environment => [:article] } + end + +end \ No newline at end of file diff --git a/plugins/relevant_content/public/style.css b/plugins/relevant_content/public/style.css new file mode 100644 index 0000000..b0327fc --- /dev/null +++ b/plugins/relevant_content/public/style.css @@ -0,0 +1,79 @@ +#content .relevant-content-plugin_relevant-content-block { + padding: 10px 0px 10px 10px; + word-wrap: break-word; +} + +.relevant-content-plugin_relevant-content-block ul { + margin: 0px; + padding: 0px 0px 0px 20px; +} +.relevant-content-plugin_relevant-content-block li { + margin: 0px; + padding: 0px; + list-style: none +} +.relevant-content-plugin_relevant-content-block a { + text-decoration: none; +} +.relevant-content-plugin_relevant-content-block .block-footer-content { + font-size: 10px; +} +.relevant-content-plugin_relevant-content-block .block-footer-content a:hover { + text-decoration: underline; +} + +.relevant-content-plugin_relevant-content-block p { + text-align:center; +} + +.relevant-content-plugin_relevant-content-block p.like{ + background-image: url('images/positive-hand.png'); + background-repeat: no-repeat; + min-width: 50px; + text-align:center; +} + +.relevant-content-plugin_relevant-content-block p.dislike{ + background-image: url('images/negative-hand.png'); + background-repeat: no-repeat; + min-width: 50px; + text-align:center; +} + + +.relevant-content-plugin_relevant-content-block { + //overflow: hidden; + display: block; + width: 100%; +} + + +.relevant-content-cover img { + width: 100%; +} + +.relevant-content-plugin_relevant-content-block span.title { + display: block; + margin: 20px 0px 0px; + padding: 0px 0px 0px 20px; +} + +.relevant-content-plugin_relevant-content-block span.title.mread { + +} + +.relevant-content-plugin_relevant-content-block span.title.mcommented { + +} + +.relevant-content-plugin_relevant-content-block span.title.mliked { + +} + +.relevant-content-plugin_relevant-content-block span.title.mdisliked { + +} + +.relevant-content-plugin_relevant-content-block span.title.mvoted { + +} diff --git a/plugins/relevant_content/test/test_helper.rb b/plugins/relevant_content/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/relevant_content/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/relevant_content/test/unit/relevant_content_block_test.rb b/plugins/relevant_content/test/unit/relevant_content_block_test.rb new file mode 100644 index 0000000..94adef4 --- /dev/null +++ b/plugins/relevant_content/test/unit/relevant_content_block_test.rb @@ -0,0 +1,217 @@ +require File.dirname(__FILE__) + '/../test_helper' + +require 'comment_controller' +# Re-raise errors caught by the controller. +class CommentController; def rescue_action(e) raise e end; end + +class RelevantContentBlockTest < ActiveSupport::TestCase + + include AuthenticatedTestHelper + fixtures :users, :environments + + def setup + @controller = CommentController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @profile = create_user('testinguser').person + @environment = @profile.environment + end + attr_reader :profile, :environment + + + + should 'have a default title' do + relevant_content_block = RelevantContentPlugin::RelevantContentBlock.new + block = Block.new + assert_not_equal block.default_title, relevant_content_block.default_title + end + + should 'have a help tooltip' do + relevant_content_block = RelevantContentPlugin::RelevantContentBlock.new + block = Block.new + assert_not_equal "", relevant_content_block.help + end + + should 'describe itself' do + assert_not_equal Block.description, RelevantContentPlugin::RelevantContentBlock.description + end + + should 'is editable' do + block = RelevantContentPlugin::RelevantContentBlock.new + assert block.editable? + end + + should 'expire' do + assert_equal RelevantContentPlugin::RelevantContentBlock.expire_on, {:environment=>[:article], :profile=>[:article]} + end + + should 'not raise an exception when finding the most accessed content' do + assert_nothing_raised{ + Article.most_accessed(Environment.default, 5) + } + end + + should 'not raise an exception when finding the most commented content' do + assert_nothing_raised{ + Article.most_commented_relevant_content(Environment.default, 5) + } + end + + should 'not raise an exception when finding the most liked content' do + begin + Environment.default.enable_plugin(:vote) + rescue + puts "Unable to activate vote plugin" + end + if Environment.default.plugin_enabled?(:vote) + assert_nothing_raised{ + Article.most_liked(Environment.default, 5) + } + end + end + + should 'not raise an exception when finding the most disliked content' do + begin + Environment.default.enable_plugin(:vote) + rescue + puts "Unable to activate vote plugin" + end + if Environment.default.plugin_enabled?(:vote) + assert_nothing_raised{ + Article.most_disliked(Environment.default, 5) + } + end + end + + + should 'not raise an exception when finding the more positive votes' do + begin + Environment.default.enable_plugin(:vote) + rescue + puts "Unable to activate vote plugin" + end + if Environment.default.plugin_enabled?(:vote) + assert_nothing_raised{ + Article.more_positive_votes(Environment.default, 5) + } + end + end + + should 'not raise an exception when finding the most voted' do + begin + Environment.default.enable_plugin(:vote) + rescue + puts "Unable to activate vote plugin" + end + if Environment.default.plugin_enabled?(:vote) + assert_nothing_raised{ + Article.most_voted(Environment.default, 5) + } + end + end + + should 'find the most voted' do + + article = fast_create(Article, {:name=>'2 votes'}) + for i in 0..2 + person = fast_create(Person) + person.vote_for(article) + end + + article = fast_create(Article, {:name=>'10 votes'}) + for i in 0..10 + person = fast_create(Person) + person.vote_for(article) + end + + article = fast_create(Article, {:name=>'5 votes'}) + for i in 0..5 + person = fast_create(Person) + person.vote_for(article) + end + + articles = Article.most_voted(Environment.default, 5) + assert_equal '10 votes', articles.first.name + assert_equal '2 votes', articles.last.name + end + + should 'list the most postive' do + + article = fast_create(Article, {:name=>'23 votes for 20 votes against'}) + for i in 0..20 + person = fast_create(Person) + person.vote_against(article) + end + for i in 0..23 + person = fast_create(Person) + person.vote_for(article) + end + + article = fast_create(Article, {:name=>'10 votes for 5 votes against'}) + for i in 0..10 + person = fast_create(Person) + person.vote_for(article) + end + for i in 0..5 + person = fast_create(Person) + person.vote_against(article) + end + + article = fast_create(Article, {:name=>'2 votes against'}) + for i in 0..2 + person = fast_create(Person) + person.vote_against(article) + end + + article = fast_create(Article, {:name=>'7 votes for'}) + for i in 0..7 + person = fast_create(Person) + person.vote_for(article) + end + + articles = Article.more_positive_votes(Environment.default, 5) + assert_equal '7 votes for', articles.first.name + assert_equal '23 votes for 20 votes against', articles.last.name + end + + should 'list the most negative' do + + article = fast_create(Article, {:name=>'23 votes for 29 votes against'}) + for i in 0..29 + person = fast_create(Person) + person.vote_against(article) + end + for i in 0..23 + person = fast_create(Person) + person.vote_for(article) + end + + article = fast_create(Article, {:name=>'10 votes for 15 votes against'}) + for i in 0..10 + person = fast_create(Person) + person.vote_for(article) + end + for i in 0..15 + person = fast_create(Person) + person.vote_against(article) + end + + article = fast_create(Article, {:name=>'2 votes against'}) + for i in 0..2 + person = fast_create(Person) + person.vote_against(article) + end + + article = fast_create(Article, {:name=>'7 votes for'}) + for i in 0..7 + person = fast_create(Person) + person.vote_for(article) + end + + articles = Article.more_negative_votes(Environment.default, 5) + assert_equal '23 votes for 29 votes against', articles.first.name + assert_equal '2 votes against', articles.last.name + end + +end diff --git a/plugins/relevant_content/test/unit/relevant_content_plugin_test.rb b/plugins/relevant_content/test/unit/relevant_content_plugin_test.rb new file mode 100644 index 0000000..434b948 --- /dev/null +++ b/plugins/relevant_content/test/unit/relevant_content_plugin_test.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class RelevantContentPluginTest < ActiveSupport::TestCase + + def setup + @plugin = RelevantContentPlugin.new + end + + should 'be a noosfero plugin' do + assert_kind_of Noosfero::Plugin, @plugin + end + + should 'have name' do + assert_equal 'Relevant Content Plugin', RelevantContentPlugin.plugin_name + end + + should 'have description' do + assert_equal _("A plugin that lists the most accessed, most commented, most liked and most disliked contents."), RelevantContentPlugin.plugin_description + end + + should 'have stylesheet' do + assert @plugin.stylesheet? + end + + should "return RelevantContentBlock in extra_blocks class method" do + assert RelevantContentPlugin.extra_blocks.keys.include?(RelevantContentPlugin::RelevantContentBlock) + end + +end diff --git a/plugins/relevant_content/views/box_organizer/relevant_content_plugin/_relevant_content_block.rhtml b/plugins/relevant_content/views/box_organizer/relevant_content_plugin/_relevant_content_block.rhtml new file mode 100644 index 0000000..b458b1a --- /dev/null +++ b/plugins/relevant_content/views/box_organizer/relevant_content_plugin/_relevant_content_block.rhtml @@ -0,0 +1,12 @@ +
+ <%= labelled_form_field _('Limit of items per category'), text_field(:block, :limit, :size => 3) %> + <%= labelled_check_box _('Display most accessed content'), "block[show_most_read]", 1 ,@block.show_most_read != 0 %>
+ <%= labelled_check_box _('Display most commented content'), "block[show_most_commented]", 1 ,@block.show_most_commented != 0 %>
+ <%= labelled_check_box _('Display most liked content'), "block[show_most_liked]", 1 ,@block.show_most_liked != 0 %>
+ <%= labelled_check_box _('Display most voted content'), "block[show_most_voted]", 1 ,@block.show_most_voted != 0 %>
+ <%= labelled_check_box _('Display most disliked content'), "block[show_most_disliked]", 1 , @block.show_most_disliked != 0 %>
+
+ + + + diff --git a/plugins/relevant_content/views/environment_design/relevant_content_plugin b/plugins/relevant_content/views/environment_design/relevant_content_plugin new file mode 120000 index 0000000..85f0ab7 --- /dev/null +++ b/plugins/relevant_content/views/environment_design/relevant_content_plugin @@ -0,0 +1 @@ +../box_organizer/relevant_content_plugin \ No newline at end of file diff --git a/plugins/relevant_content/views/profile_design/relevant_content_plugin b/plugins/relevant_content/views/profile_design/relevant_content_plugin new file mode 120000 index 0000000..85f0ab7 --- /dev/null +++ b/plugins/relevant_content/views/profile_design/relevant_content_plugin @@ -0,0 +1 @@ +../box_organizer/relevant_content_plugin \ No newline at end of file -- libgit2 0.21.2