diff --git a/lib/proposals_discussion_plugin.rb b/lib/proposals_discussion_plugin.rb new file mode 100644 index 0000000..6b2c097 --- /dev/null +++ b/lib/proposals_discussion_plugin.rb @@ -0,0 +1,36 @@ +class ProposalsDiscussionPlugin < Noosfero::Plugin + + def self.plugin_name + 'Discussion of Proposals' + end + + def self.plugin_description + _("Provide a structured way to promove a discussion over ideas proposed by users.") + end + + def stylesheet? + true + end + + def content_types + if context.respond_to?(:params) && context.params + types = [] + parent_id = context.params[:parent_id] + parent = parent_id ? context.profile.articles.find(parent_id) : nil + types << ProposalsDiscussionPlugin::Discussion unless parent + types << ProposalsDiscussionPlugin::Proposal if parent.kind_of?(ProposalsDiscussionPlugin::Discussion) + types + else + [ProposalsDiscussionPlugin::Discussion, ProposalsDiscussionPlugin::Proposal] + end + end + + def content_remove_new(page) + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || page.kind_of?(ProposalsDiscussionPlugin::Proposal) + end + + def content_remove_upload(page) + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || page.kind_of?(ProposalsDiscussionPlugin::Proposal) + end + +end diff --git a/lib/proposals_discussion_plugin/discussion.rb b/lib/proposals_discussion_plugin/discussion.rb new file mode 100644 index 0000000..daeb514 --- /dev/null +++ b/lib/proposals_discussion_plugin/discussion.rb @@ -0,0 +1,18 @@ +class ProposalsDiscussionPlugin::Discussion < Folder + + def self.short_description + _("Discussion") + end + + def self.description + _('Container for proposals.') + end + + def to_html(options = {}) + discussion = self + proc do + render :file => 'content_viewer/discussion', :locals => {:discussion => discussion} + end + end + +end diff --git a/lib/proposals_discussion_plugin/proposal.rb b/lib/proposals_discussion_plugin/proposal.rb new file mode 100644 index 0000000..3863246 --- /dev/null +++ b/lib/proposals_discussion_plugin/proposal.rb @@ -0,0 +1,13 @@ +class ProposalsDiscussionPlugin::Proposal < TinyMceArticle + + def self.short_description + _("Proposal") + end + + def self.description + _('Proposal') + end + + validates_presence_of :abstract + +end diff --git a/public/images/comments.gif b/public/images/comments.gif new file mode 100644 index 0000000..e3982a9 Binary files /dev/null and b/public/images/comments.gif differ diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..1d2d44f --- /dev/null +++ b/public/style.css @@ -0,0 +1,80 @@ +.proposal { + background: rgb(236, 236, 236); + width: 31%; + min-width: 272px; + display: inline-block; + vertical-align: top; + margin: 5px 13px 5px 0; + box-shadow: 5px 5px 5px -2px #ddd; +} + +.proposal:hover { + background: rgb(223, 223, 223); +} + +.proposal .title { + background: rgba(0, 0, 0, 0.1); + font-weight: bold; + font-size: 15px; +} + +#article .proposal a:visited, #article .proposal a { + color: rgb(94, 94, 94); + text-decoration: none; + width: 100%; + display: inline-block; +} + +#article .proposal .title { + padding: 0px 5px; +} + +#article .proposal .title a { + padding: 8px 0px; +} + +.proposal .content { + padding: 5px; + color: rgb(83, 83, 83); +} + +.proposal .abstract { + padding-top: 8px; +} + +.proposal .info { + float: left; +} + +.proposal .info .comments { + background: url('/plugins/proposals_discussion/images/comments.gif') no-repeat left/15px; + padding-left: 18px; + display: inline; + font-size: 10px; + color: rgb(82, 82, 82); + opacity: 0.6; +} + +.proposal .actions { + float: right; +} + +.proposal .actions .vote-actions { + position: static; +} + +.proposal .actions .vote-actions .vote-action a { + opacity: 0.6; +} + +form .proposals-discussion-plugin textarea { + width: 98%; +} + +form .proposals-discussion-plugin .abstract textarea { + height: 60px; +} + +form .proposals-discussion-plugin .body textarea { + height: 400px; +} diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/test/unit/proposal_test.rb b/test/unit/proposal_test.rb new file mode 100644 index 0000000..aa093ca --- /dev/null +++ b/test/unit/proposal_test.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ProposalsDiscussionPluginTest < ActiveSupport::TestCase + + def setup + @profile = fast_create(Community) + @proposal = ProposalsDiscussionPlugin::Proposal.new(:name => 'test', :profile => @profile) + end + + attr_reader :profile, :proposal + + should 'save a proposal' do + proposal.abstract = 'abstract' + assert proposal.save + end + + should 'do not save a proposal without abstract' do + proposal.save + assert proposal.errors['abstract'].present? + end + +end diff --git a/test/unit/proposals_discussion_plugin_test.rb b/test/unit/proposals_discussion_plugin_test.rb new file mode 100644 index 0000000..2c69cdc --- /dev/null +++ b/test/unit/proposals_discussion_plugin_test.rb @@ -0,0 +1,70 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ProposalsDiscussionPluginTest < ActiveSupport::TestCase + + def setup + @plugin = ProposalsDiscussionPlugin.new + @profile = fast_create(Community) + @params = {} + @plugin.stubs(:context).returns(self) + end + + attr_reader :plugin, :profile, :params + + should 'has stylesheet' do + assert @plugin.stylesheet? + end + + should 'return Discussion as a content type' do + @params[:parent_id] = nil + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion + end + + should 'do not return Discussion as a content type if it has a parent' do + parent = fast_create(Folder, :profile_id => @profile.id) + @params[:parent_id] = parent.id + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion + end + + should 'return Proposal as a content type if parent is a Discussion' do + parent = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) + @params[:parent_id] = parent.id + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal + end + + should 'do not return Proposal as a content type if parent is nil' do + @params[:parent_id] = nil + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal + end + + should 'remove new button from content page for a discussion' do + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) + assert plugin.content_remove_new(page) + end + + should 'remove upload button from content page for a discussion' do + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) + assert plugin.content_remove_upload(page) + end + + should 'remove new button from content page for a proposal' do + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) + assert plugin.content_remove_new(page) + end + + should 'remove upload button from content page for a proposal' do + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) + assert plugin.content_remove_upload(page) + end + + should 'do not remove new button from content page for others article types' do + page = fast_create(Article, :profile_id => @profile.id) + assert !plugin.content_remove_new(page) + end + + should 'do not remove upload button from content page for others article types' do + page = fast_create(Article, :profile_id => @profile.id) + assert !plugin.content_remove_upload(page) + end + +end diff --git a/views/cms/proposals_discussion_plugin/_proposal.html.erb b/views/cms/proposals_discussion_plugin/_proposal.html.erb new file mode 100644 index 0000000..74b5124 --- /dev/null +++ b/views/cms/proposals_discussion_plugin/_proposal.html.erb @@ -0,0 +1,28 @@ +<%= required_fields_message %> + +<%= render :file => 'shared/tiny_mce' %> + +<% title_limit = 70 %> +<% abstract_limit = 140 %> + +