diff --git a/plugins/dspace/lib/dspace_plugin.rb b/plugins/dspace/lib/dspace_plugin.rb new file mode 100644 index 0000000..1dfc482 --- /dev/null +++ b/plugins/dspace/lib/dspace_plugin.rb @@ -0,0 +1,21 @@ +class DspacePlugin < 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 + { + DspacePlugin::DspaceBlock => {} + } + end + + def stylesheet? + true + end + +end diff --git a/plugins/dspace/lib/dspace_plugin/dspace_block.rb b/plugins/dspace/lib/dspace_plugin/dspace_block.rb new file mode 100644 index 0000000..2b3b6d2 --- /dev/null +++ b/plugins/dspace/lib/dspace_plugin/dspace_block.rb @@ -0,0 +1,97 @@ +class DspacePlugin::DspaceBlock < Block + def self.description + _('Dspace content') + end + + def default_title + _('Dspace content') + end + + def help + _('This block displays dspace content.') + end + + settings_items :limit, :type => :integer, :default => 5 + settings_items :show_most_read, :type => :boolean, :default => 1 + settings_items :show_most_commented, :type => :boolean, :default => 1 + settings_items :show_most_liked, :type => :boolean, :default => 1 + settings_items :show_most_disliked, :type => :boolean, :default => 0 + settings_items :show_most_voted, :type => :boolean, :default => 1 + + attr_accessible :limit, :show_most_voted, :show_most_disliked, :show_most_liked, :show_most_commented, :show_most_read + + include ActionView::Helpers + include Rails.application.routes.url_helpers + + def content(args={}) + + content = block_title(title) + + if self.show_most_read + 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 + docs = Article.most_commented_dspace(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 + 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 + 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 + 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 diff --git a/plugins/dspace/lib/ext/article.rb b/plugins/dspace/lib/ext/article.rb new file mode 100644 index 0000000..659fe60 --- /dev/null +++ b/plugins/dspace/lib/ext/article.rb @@ -0,0 +1,95 @@ +require_dependency 'article' + +class Article + + scope :dspace, :conditions => ["articles.published = true and (articles.type != 'UploadedFile' and articles.type != 'Blog' and articles.type != 'RssFeed') OR articles.type is NULL"] + + def self.articles_columns + Article.column_names.map {|c| "articles.#{c}"} .join(",") + end + + def self.most_accessed(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? ["hits > 0"] : ["profile_id = ? and hits > 0", owner.id] + result = Article.dspace.find( + :all, + :order => 'hits desc', + :limit => limit, + :conditions => conditions) + result.paginate({:page => 1, :per_page => limit}) + end + + def self.most_commented_dspace(owner, limit) + conditions = owner.kind_of?(Environment) ? ["comments_count > 0"] : ["profile_id = ? and comments_count > 0", owner.id] + result = Article.dspace.find( + :all, + :order => 'comments_count desc', + :limit => limit, + :conditions => conditions) + result.paginate({:page => 1, :per_page => limit}) + end + + def self.more_positive_votes(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? {'votes.voteable_type' => 'Article'} : ["profile_id = ? and votes.voteable_type = ? ", owner.id, 'Article'] + result = Article.dspace.find( + :all, + :order => 'sum(vote) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :having => ['sum(vote) > 0'], + :conditions => conditions, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id') + result.paginate({:page => 1, :per_page => limit}) + end + + def self.more_negative_votes(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? {'votes.voteable_type' => 'Article'} : ["profile_id = ? and votes.voteable_type = 'Article' ", owner.id] + result = Article.dspace.find( + :all, + :order => 'sum(vote) asc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :having => ['sum(vote) < 0'], + :conditions => conditions, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id' + ) + result.paginate({:page => 1, :per_page => limit}) + end + + def self.most_liked(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? ["votes.voteable_type = 'Article' and vote > 0"] : ["votes.voteable_type = 'Article' and vote > 0 and profile_id = ? ", owner.id] + result = Article.dspace.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :conditions => conditions, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id') + result.paginate({:page => 1, :per_page => limit}) + end + + def self.most_disliked(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? ["votes.voteable_type = 'Article' and vote < 0"] : ["votes.voteable_type = 'Article' and vote < 0 and profile_id = ? ", owner.id] + result = Article.dspace.find( + :all, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :conditions => conditions, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id') + result.paginate({:page => 1, :per_page => limit}) + end + + def self.most_voted(owner, limit = nil) + conditions = owner.kind_of?(Environment) ? ["votes.voteable_type = 'Article'"] : ["votes.voteable_type = 'Article' and profile_id = ? ", owner.id] + result = Article.dspace.find( + :all, + :select => articles_columns, + :order => 'count(voteable_id) desc', + :group => 'voteable_id, ' + articles_columns, + :limit => limit, + :conditions => conditions, + :joins => 'INNER JOIN votes ON articles.id = votes.voteable_id') + result.paginate({:page => 1, :per_page => limit}) + end +end diff --git a/plugins/dspace/public/style.css b/plugins/dspace/public/style.css new file mode 100644 index 0000000..c7dc261 --- /dev/null +++ b/plugins/dspace/public/style.css @@ -0,0 +1,79 @@ +#content .dspace-plugin_dspace-block { + padding: 10px 0px 10px 10px; + word-wrap: break-word; +} + +.dspace-plugin_dspace-block ul { + margin: 0px; + padding: 0px 0px 0px 20px; +} +.dspace-plugin_dspace-block li { + margin: 0px; + padding: 0px; + list-style: none +} +.dspace-plugin_dspace-block a { + text-decoration: none; +} +.dspace-plugin_dspace-block .block-footer-content { + font-size: 10px; +} +.dspace-plugin_dspace-block .block-footer-content a:hover { + text-decoration: underline; +} + +.dspace-plugin_dspace-block p { + text-align:center; +} + +.dspace-plugin_dspace-block p.like{ + background-image: url('images/positive-hand.png'); + background-repeat: no-repeat; + min-width: 50px; + text-align:center; +} + +.dspace-plugin_dspace-block p.dislike{ + background-image: url('images/negative-hand.png'); + background-repeat: no-repeat; + min-width: 50px; + text-align:center; +} + + +.dspace-plugin_dspace-block { + //overflow: hidden; + display: block; + width: 100%; +} + + +.dspace-cover img { + width: 100%; +} + +.dspace-plugin_dspace-block span.title { + display: block; + margin: 20px 0px 0px; + padding: 0px 0px 0px 20px; +} + +.dspace-plugin_dspace-block span.title.mread { + +} + +.dspace-plugin_dspace-block span.title.mcommented { + +} + +.dspace-plugin_dspace-block span.title.mliked { + +} + +.dspace-plugin_dspace-block span.title.mdisliked { + +} + +.dspace-plugin_dspace-block span.title.mvoted { + +} diff --git a/plugins/dspace/test/test_helper.rb b/plugins/dspace/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/dspace/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/dspace/test/unit/article.rb b/plugins/dspace/test/unit/article.rb new file mode 100644 index 0000000..64ecbcb --- /dev/null +++ b/plugins/dspace/test/unit/article.rb @@ -0,0 +1,148 @@ +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 DspaceBlockTest < 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 + + def enable_vote_plugin + enabled = false + environment=Environment.default + if Noosfero::Plugin.all.include?('VotePlugin') + if not environment.enabled_plugins.include?(:vote) + environment.enable_plugin(Vote) + environment.save! + end + enabled = true + end + enabled + end + + should 'list most commented articles' do + Article.delete_all + a1 = create(TextileArticle, :name => "art 1", :profile_id => profile.id) + a2 = create(TextileArticle, :name => "art 2", :profile_id => profile.id) + a3 = create(TextileArticle, :name => "art 3", :profile_id => profile.id) + + 2.times { Comment.create(:title => 'test', :body => 'asdsad', :author => profile, :source => a2).save! } + 4.times { Comment.create(:title => 'test', :body => 'asdsad', :author => profile, :source => a3).save! } + + # should respect the order (more commented comes first) + assert_equal a3.name, profile.articles.most_commented_dspace(Environment.default, 3).first.name + # It is a2 instead of a1 since it does not list articles without comments + assert_equal a2.name, profile.articles.most_commented_dspace(Environment.default, 3).last.name + end + + + should 'find the most voted' do + if not enable_vote_plugin + return + end + article = fast_create(Article, {:name=>'2 votes'}) + 2.times{ + person = fast_create(Person) + person.vote_for(article) + } + article = fast_create(Article, {:name=>'10 votes'}) + 10.times{ + person = fast_create(Person) + person.vote_for(article) + } + article = fast_create(Article, {:name=>'5 votes'}) + 5.times{ + person = fast_create(Person) + person.vote_for(article) + } + 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 + if not enable_vote_plugin + return + end + article = fast_create(Article, {:name=>'23 votes for 20 votes against'}) + 20.times{ + person = fast_create(Person) + person.vote_against(article) + } + 23.times{ + person = fast_create(Person) + person.vote_for(article) + } + article = fast_create(Article, {:name=>'10 votes for 5 votes against'}) + 10.times{ + person = fast_create(Person) + person.vote_for(article) + } + 5.times{ + person = fast_create(Person) + person.vote_against(article) + } + article = fast_create(Article, {:name=>'2 votes against'}) + 2.times{ + person = fast_create(Person) + person.vote_against(article) + } + + article = fast_create(Article, {:name=>'7 votes for'}) + 7.times{ + person = fast_create(Person) + person.vote_for(article) + } + 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 + if not enable_vote_plugin + return + end + article = fast_create(Article, {:name=>'23 votes for 29 votes against'}) + 29.times{ + person = fast_create(Person) + person.vote_against(article) + } + 23.times{ + person = fast_create(Person) + person.vote_for(article) + } + article = fast_create(Article, {:name=>'10 votes for 15 votes against'}) + 10.times{ + person = fast_create(Person) + person.vote_for(article) + } + 15.times{ + person = fast_create(Person) + person.vote_against(article) + } + article = fast_create(Article, {:name=>'2 votes against'}) + 2.times{ + person = fast_create(Person) + person.vote_against(article) + } + article = fast_create(Article, {:name=>'7 votes for'}) + 7.times{ + person = fast_create(Person) + person.vote_for(article) + } + 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 \ No newline at end of file diff --git a/plugins/dspace/test/unit/dspace_block_test.rb b/plugins/dspace/test/unit/dspace_block_test.rb new file mode 100644 index 0000000..24f8b49 --- /dev/null +++ b/plugins/dspace/test/unit/dspace_block_test.rb @@ -0,0 +1,47 @@ +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 DspaceBlockTest < 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 + dspace_block = DspacePlugin::DspaceBlock.new + block = Block.new + assert_not_equal block.default_title, dspace_block.default_title + end + + should 'have a help tooltip' do + dspace_block = DspacePlugin::DspaceBlock.new + block = Block.new + assert_not_equal "", dspace_block.help + end + + should 'describe itself' do + assert_not_equal Block.description, DspacePlugin::DspaceBlock.description + end + + should 'is editable' do + block = DspacePlugin::DspaceBlock.new + assert block.editable? + end + + should 'expire' do + assert_equal DspacePlugin::DspaceBlock.expire_on, {:environment=>[:article], :profile=>[:article]} + end + +end diff --git a/plugins/dspace/test/unit/dspace_plugin_test.rb b/plugins/dspace/test/unit/dspace_plugin_test.rb new file mode 100644 index 0000000..08087c5 --- /dev/null +++ b/plugins/dspace/test/unit/dspace_plugin_test.rb @@ -0,0 +1,29 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class DspacePluginTest < ActiveSupport::TestCase + + def setup + @plugin = DspacePlugin.new + end + + should 'be a noosfero plugin' do + assert_kind_of Noosfero::Plugin, @plugin + end + + should 'have name' do + assert_equal 'Relevant Content Plugin', DspacePlugin.plugin_name + end + + should 'have description' do + assert_equal _("A plugin that lists the most accessed, most commented, most liked and most disliked contents."), DspacePlugin.plugin_description + end + + should 'have stylesheet' do + assert @plugin.stylesheet? + end + + should "return DspaceBlock in extra_blocks class method" do + assert DspacePlugin.extra_blocks.keys.include?(DspacePlugin::DspaceBlock) + end + +end diff --git a/plugins/dspace/views/box_organizer/dspace_plugin/_dspace_block.html.erb b/plugins/dspace/views/box_organizer/dspace_plugin/_dspace_block.html.erb new file mode 100644 index 0000000..4322476 --- /dev/null +++ b/plugins/dspace/views/box_organizer/dspace_plugin/_dspace_block.html.erb @@ -0,0 +1,8 @@ +
+ <%= 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 %>
+ <%= labelled_check_box _('Display most commented content'), "block[show_most_commented]", 1 ,@block.show_most_commented %>
+ <%= labelled_check_box _('Display most liked content'), "block[show_most_liked]", 1 ,@block.show_most_liked %>
+ <%= labelled_check_box _('Display most voted content'), "block[show_most_voted]", 1 ,@block.show_most_voted %>
+ <%= labelled_check_box _('Display most disliked content'), "block[show_most_disliked]", 1 , @block.show_most_disliked %>
+
\ No newline at end of file -- libgit2 0.21.2