Commit 29490ac8337e1b6cc16ea20d6be529075b4ced9a
Exists in
staging
and in
4 other branches
Merge branch 'AI3220_proposals' into rails3_stable
Showing
35 changed files
with
905 additions
and
6 deletions
Show diff stats
app/controllers/admin/features_controller.rb
@@ -93,7 +93,7 @@ class FeaturesController < AdminController | @@ -93,7 +93,7 @@ class FeaturesController < AdminController | ||
93 | 93 | ||
94 | def search_members | 94 | def search_members |
95 | arg = params[:q].downcase | 95 | arg = params[:q].downcase |
96 | - result = environment.people.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"]) | 96 | + result = environment.people.find(:all, :conditions => ['LOWER(name) LIKE ? OR identifier LIKE ?', "%#{arg}%", "%#{arg}%"]) |
97 | render :text => prepare_to_token_input(result).to_json | 97 | render :text => prepare_to_token_input(result).to_json |
98 | end | 98 | end |
99 | 99 |
app/helpers/categories_helper.rb
@@ -12,7 +12,7 @@ module CategoriesHelper | @@ -12,7 +12,7 @@ module CategoriesHelper | ||
12 | end | 12 | end |
13 | 13 | ||
14 | def category_color_style(category) | 14 | def category_color_style(category) |
15 | - return '' if category.display_color.blank? | 15 | + return '' if category.nil? or category.display_color.blank? |
16 | 'background-color: #'+category.display_color+';' | 16 | 'background-color: #'+category.display_color+';' |
17 | end | 17 | end |
18 | 18 |
app/models/article.rb
@@ -252,7 +252,7 @@ class Article < ActiveRecord::Base | @@ -252,7 +252,7 @@ class Article < ActiveRecord::Base | ||
252 | } | 252 | } |
253 | 253 | ||
254 | scope :public, | 254 | scope :public, |
255 | - :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ], :joins => [:profile] | 255 | + :conditions => [ "articles.advertise = ? AND articles.published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ], :joins => [:profile] |
256 | 256 | ||
257 | scope :more_recent, | 257 | scope :more_recent, |
258 | :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND | 258 | :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND |
features/step_definitions/web_steps.rb
@@ -11,8 +11,14 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "pat | @@ -11,8 +11,14 @@ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "pat | ||
11 | 11 | ||
12 | module WithinHelpers | 12 | module WithinHelpers |
13 | def with_scope(locator) | 13 | def with_scope(locator) |
14 | - locator = locator ? first(locator) : locator | ||
15 | - locator ? within(locator) { yield } : yield | 14 | + if locator |
15 | + locator = first(locator) || locator | ||
16 | + within(locator) do | ||
17 | + yield | ||
18 | + end | ||
19 | + else | ||
20 | + yield | ||
21 | + end | ||
16 | end | 22 | end |
17 | end | 23 | end |
18 | World(WithinHelpers) | 24 | World(WithinHelpers) |
plugins/proposals_discussion/controllers/myprofile/proposals_discussion_plugin_myprofile_controller.rb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +class ProposalsDiscussionPluginMyprofileController < MyProfileController | ||
2 | + | ||
3 | + before_filter :check_edit_permission_to_proposal, :only => :publish_proposal | ||
4 | + | ||
5 | + def select_topic | ||
6 | + @discussion = profile.articles.find(params[:parent_id]) | ||
7 | + render :file => 'select_topic' | ||
8 | + end | ||
9 | + | ||
10 | + def new_proposal | ||
11 | + redirect_to :controller => 'cms', :action => 'new', :type => "ProposalsDiscussionPlugin::Proposal", :parent_id => params[:discussion][:topic] | ||
12 | + end | ||
13 | + | ||
14 | + def publish_proposal | ||
15 | + if @proposal.update_attribute(:published, true) | ||
16 | + session[:notice] = _('Proposal published!') | ||
17 | + else | ||
18 | + session[:notice] = _('Failed to publish your proposal.') | ||
19 | + end | ||
20 | + redirect_to @proposal.topic.view_url | ||
21 | + end | ||
22 | + | ||
23 | + protected | ||
24 | + | ||
25 | + def check_edit_permission_to_proposal | ||
26 | + @proposal = profile.articles.find(params[:proposal_id]) | ||
27 | + render_access_denied unless @proposal.allow_edit?(user) | ||
28 | + end | ||
29 | + | ||
30 | +end |
plugins/proposals_discussion/controllers/public/proposals_discussion_plugin_public_controller.rb
0 → 100644
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +class ProposalsDiscussionPluginPublicController < ApplicationController | ||
2 | + | ||
3 | + needs_profile | ||
4 | + | ||
5 | + def load_proposals | ||
6 | + holder = profile.articles.find(params[:holder_id]) | ||
7 | + page = (params[:page] || 1).to_i | ||
8 | + set_rand_cookie if page == 1 | ||
9 | + order = params[:order] | ||
10 | + | ||
11 | + @proposals = order_proposals(holder.proposals.public, order) | ||
12 | + @proposals = @proposals.page(page).per_page(5) | ||
13 | + | ||
14 | + unless @proposals.empty? | ||
15 | + render :partial => 'content_viewer/proposals_list_content', :locals => {:proposals => @proposals, :holder => holder, :page => page+1, :order => order} | ||
16 | + else | ||
17 | + render :text => '' | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + private | ||
22 | + | ||
23 | + def order_proposals(proposals, order) | ||
24 | + case order | ||
25 | + when 'alphabetical' | ||
26 | + proposals.reorder('name') | ||
27 | + else | ||
28 | + set_seed | ||
29 | + proposals.reorder('random()') | ||
30 | + end | ||
31 | + end | ||
32 | + | ||
33 | + def set_seed | ||
34 | + #XXX postgresql specific | ||
35 | + seed_val = profile.connection.quote(cookies[:_noosfero_proposals_discussion_rand_seed]) | ||
36 | + profile.connection.execute("select setseed(#{seed_val})") | ||
37 | + end | ||
38 | + | ||
39 | + def set_rand_cookie | ||
40 | + cookies[:_noosfero_proposals_discussion_rand_seed] = {value: rand, expires: Time.now + 600} | ||
41 | + end | ||
42 | + | ||
43 | +end |
plugins/proposals_discussion/lib/proposals_discussion_plugin.rb
0 → 100644
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +class ProposalsDiscussionPlugin < Noosfero::Plugin | ||
2 | + | ||
3 | + def self.plugin_name | ||
4 | + 'Discussion of Proposals' | ||
5 | + end | ||
6 | + | ||
7 | + def self.plugin_description | ||
8 | + _("Provide a structured way to promove a discussion over ideas proposed by users.") | ||
9 | + end | ||
10 | + | ||
11 | + def stylesheet? | ||
12 | + true | ||
13 | + end | ||
14 | + | ||
15 | + def content_types | ||
16 | + if context.respond_to?(:params) && context.params | ||
17 | + types = [] | ||
18 | + parent_id = context.params[:parent_id] | ||
19 | + parent = parent_id ? context.profile.articles.find(parent_id) : nil | ||
20 | + types << ProposalsDiscussionPlugin::Discussion unless parent | ||
21 | + types << ProposalsDiscussionPlugin::Topic if parent.kind_of?(ProposalsDiscussionPlugin::Discussion) | ||
22 | + types << ProposalsDiscussionPlugin::Proposal if parent.kind_of?(ProposalsDiscussionPlugin::Topic) | ||
23 | + types | ||
24 | + else | ||
25 | + [ProposalsDiscussionPlugin::Discussion, | ||
26 | + ProposalsDiscussionPlugin::Topic, | ||
27 | + ProposalsDiscussionPlugin::Proposal] | ||
28 | + end | ||
29 | + end | ||
30 | + | ||
31 | + def content_remove_new(page) | ||
32 | + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || | ||
33 | + page.kind_of?(ProposalsDiscussionPlugin::Topic) || | ||
34 | + page.kind_of?(ProposalsDiscussionPlugin::Proposal) | ||
35 | + end | ||
36 | + | ||
37 | + def content_remove_upload(page) | ||
38 | + page.kind_of?(ProposalsDiscussionPlugin::Discussion) || | ||
39 | + page.kind_of?(ProposalsDiscussionPlugin::Topic) || | ||
40 | + page.kind_of?(ProposalsDiscussionPlugin::Proposal) | ||
41 | + end | ||
42 | + | ||
43 | +end |
plugins/proposals_discussion/lib/proposals_discussion_plugin/discussion.rb
0 → 100644
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +class ProposalsDiscussionPlugin::Discussion < Folder | ||
2 | + | ||
3 | + has_many :topics, :class_name => 'ProposalsDiscussionPlugin::Topic', :foreign_key => 'parent_id' | ||
4 | + has_many :proposals, :class_name => 'ProposalsDiscussionPlugin::Proposal', :through => :children, :source => :children | ||
5 | + | ||
6 | + def self.short_description | ||
7 | + _("Discussion") | ||
8 | + end | ||
9 | + | ||
10 | + def self.description | ||
11 | + _('Container for topics.') | ||
12 | + end | ||
13 | + | ||
14 | + def to_html(options = {}) | ||
15 | + proc do | ||
16 | + render :file => 'content_viewer/discussion' | ||
17 | + end | ||
18 | + end | ||
19 | + | ||
20 | +end |
plugins/proposals_discussion/lib/proposals_discussion_plugin/proposal.rb
0 → 100644
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +class ProposalsDiscussionPlugin::Proposal < TinyMceArticle | ||
2 | + | ||
3 | + scope :private, lambda {|user| {:conditions => {:last_changed_by_id => user.id, :published => false}}} | ||
4 | + | ||
5 | + alias :topic :parent | ||
6 | + | ||
7 | + def self.short_description | ||
8 | + _("Proposal") | ||
9 | + end | ||
10 | + | ||
11 | + def self.description | ||
12 | + _('Proposal') | ||
13 | + end | ||
14 | + | ||
15 | + validates_presence_of :abstract | ||
16 | + | ||
17 | + | ||
18 | + def to_html(options = {}) | ||
19 | + proc do | ||
20 | + render :file => 'content_viewer/proposal' | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + def allow_edit?(user) | ||
25 | + super || created_by == user | ||
26 | + end | ||
27 | + | ||
28 | +end |
plugins/proposals_discussion/lib/proposals_discussion_plugin/proposal_helper.rb
0 → 100644
plugins/proposals_discussion/lib/proposals_discussion_plugin/proposals_list_helper.rb
0 → 100644
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +module ProposalsDiscussionPlugin::ProposalsListHelper | ||
2 | + | ||
3 | + def more_proposals(text, holder, order, page=1) | ||
4 | + link_to '', url_for({:controller => 'proposals_discussion_plugin_public', :action => 'load_proposals', :holder_id => holder.id, :profile => profile.identifier, :order => order, :page => page }) | ||
5 | + end | ||
6 | + | ||
7 | +end |
plugins/proposals_discussion/lib/proposals_discussion_plugin/topic.rb
0 → 100644
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +class ProposalsDiscussionPlugin::Topic < Folder | ||
2 | + | ||
3 | + alias :discussion :parent | ||
4 | + | ||
5 | + has_many :proposals, :class_name => 'ProposalsDiscussionPlugin::Proposal', :foreign_key => 'parent_id' | ||
6 | + has_many :proposals_comments, :class_name => 'Comment', :through => :children, :source => :comments | ||
7 | + has_many :proposals_authors, :class_name => 'Person', :through => :children, :source => :created_by | ||
8 | + | ||
9 | + settings_items :color, :type => :string | ||
10 | + | ||
11 | + attr_accessible :color | ||
12 | + | ||
13 | + def self.short_description | ||
14 | + _("Discussion topic") | ||
15 | + end | ||
16 | + | ||
17 | + def self.description | ||
18 | + _('Container for proposals.') | ||
19 | + end | ||
20 | + | ||
21 | + def most_active_participants | ||
22 | + proposals_authors.group('profiles.id').order('count(articles.id) DESC').includes(:environment, :preferred_domain, :image) | ||
23 | + end | ||
24 | + | ||
25 | + def to_html(options = {}) | ||
26 | + proc do | ||
27 | + render :file => 'content_viewer/topic' | ||
28 | + end | ||
29 | + end | ||
30 | + | ||
31 | + def allow_create?(user) | ||
32 | + true | ||
33 | + end | ||
34 | + | ||
35 | +end |
1.66 KB
plugins/proposals_discussion/public/jquery.jscroll.min.js
0 → 100644
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +/*! | ||
2 | + * jScroll - jQuery Plugin for Infinite Scrolling / Auto-Paging - v2.2.4 | ||
3 | + * http://jscroll.com/ | ||
4 | + * | ||
5 | + * Copyright 2011-2013, Philip Klauzinski | ||
6 | + * http://klauzinski.com/ | ||
7 | + * Dual licensed under the MIT and GPL Version 2 licenses. | ||
8 | + * http://jscroll.com/#license | ||
9 | + * http://www.opensource.org/licenses/mit-license.php | ||
10 | + * http://www.gnu.org/licenses/gpl-2.0.html | ||
11 | + * | ||
12 | + * @author Philip Klauzinski | ||
13 | + * @requires jQuery v1.4.3+ | ||
14 | + */ | ||
15 | +(function(b){b.jscroll={defaults:{debug:false,autoTrigger:true,autoTriggerUntil:false,loadingHtml:"<small>Loading...</small>",padding:0,nextSelector:"a:last",contentSelector:"",pagingSelector:"",callback:false}};var a=function(e,g){var o=e.data("jscroll"),n=(typeof g==="function")?{callback:g}:g,p=b.extend({},b.jscroll.defaults,n,o||{}),c=(e.css("overflow-y")==="visible"),l=e.find(p.nextSelector).first(),v=b(window),h=b("body"),q=c?v:e,m=b.trim(l.attr("href")+" "+p.contentSelector);e.data("jscroll",b.extend({},o,{initialized:true,waiting:false,nextHref:m}));r();k();t();function k(){var x=b(p.loadingHtml).filter("img").attr("src");if(x){var w=new Image();w.src=x}}function r(){if(!e.find(".jscroll-inner").length){e.contents().wrapAll('<div class="jscroll-inner" />')}}function d(w){if(p.pagingSelector){var x=w.closest(p.pagingSelector).hide()}else{var x=w.parent().not(".jscroll-inner,.jscroll-added").addClass("jscroll-next-parent").hide();if(!x.length){w.wrap('<div class="jscroll-next-parent" />').parent().hide()}}}function j(){return q.unbind(".jscroll").removeData("jscroll").find(".jscroll-inner").children().unwrap().filter(".jscroll-added").children().unwrap()}function i(){r();var D=e.find("div.jscroll-inner").first(),B=e.data("jscroll"),C=parseInt(e.css("borderTopWidth")),y=isNaN(C)?0:C,x=parseInt(e.css("paddingTop"))+y,A=c?q.scrollTop():e.offset().top,z=D.length?D.offset().top:0,w=Math.ceil(A-z+q.height()+x);if(!B.waiting&&w+p.padding>=D.outerHeight()){f("info","jScroll:",D.outerHeight()-w,"from bottom. Loading next request...");return u()}}function s(w){w=w||e.data("jscroll");if(!w||!w.nextHref){f("warn","jScroll: nextSelector not found - destroying");j();return false}else{t();return true}}function t(){var w=e.find(p.nextSelector).first();if(p.autoTrigger&&(p.autoTriggerUntil===false||p.autoTriggerUntil>0)){d(w);if(h.height()<=v.height()){i()}q.unbind(".jscroll").bind("scroll.jscroll",function(){return i()});if(p.autoTriggerUntil>0){p.autoTriggerUntil--}}else{q.unbind(".jscroll");w.bind("click.jscroll",function(){d(w);u();return false})}}function u(){var x=e.find("div.jscroll-inner").first(),w=e.data("jscroll");w.waiting=true;x.append('<div class="jscroll-added" />').children(".jscroll-added").last().html('<div class="jscroll-loading">'+p.loadingHtml+"</div>");return e.animate({scrollTop:x.outerHeight()},0,function(){x.find("div.jscroll-added").last().load(w.nextHref,function(A,z,B){if(z==="error"){return j()}var y=b(this).find(p.nextSelector).first();w.waiting=false;w.nextHref=y.attr("href")?b.trim(y.attr("href")+" "+p.contentSelector):false;b(".jscroll-next-parent",e).remove();s();if(p.callback){p.callback.call(this)}f("dir",w)})})}function f(w){if(p.debug&&typeof console==="object"&&(typeof w==="object"||typeof console[w]==="function")){if(typeof w==="object"){var y=[];for(var x in w){if(typeof console[x]==="function"){y=(w[x].length)?w[x]:[w[x]];console[x].apply(console,y)}else{console.log.apply(console,y)}}}else{console[w].apply(console,Array.prototype.slice.call(arguments,1))}}}b.extend(e.jscroll,{destroy:j});return e};b.fn.jscroll=function(c){return this.each(function(){var f=b(this),e=f.data("jscroll");if(e&&e.initialized){return}var d=new a(f,c)})}})(jQuery); | ||
0 | \ No newline at end of file | 16 | \ No newline at end of file |
@@ -0,0 +1,31 @@ | @@ -0,0 +1,31 @@ | ||
1 | +function initTwitterButton() { | ||
2 | + !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs'); | ||
3 | +} | ||
4 | + | ||
5 | +jQuery(document).ready(function($) { | ||
6 | + initTwitterButton(); | ||
7 | + $('.proposals').on('mouseenter', '.proposal', function() { | ||
8 | + twttr.widgets.load(); | ||
9 | + $('.proposal .social').hide(); | ||
10 | + $(this).find('.social').show("fast"); | ||
11 | + }).on('mouseleave', '.proposal', function() { | ||
12 | + $(this).find('.social').hide("fast"); | ||
13 | + }); | ||
14 | + | ||
15 | + function proposalsScroll() { | ||
16 | + $('.proposals').data('jscroll', null); | ||
17 | + $('.proposals').jscroll({ | ||
18 | + loadingHtml: '<img src="/images/loading.gif" alt="Loading" />Loading...', | ||
19 | + nextSelector: 'div.more a' | ||
20 | + }); | ||
21 | + $('.proposals').trigger('scroll.jscroll'); | ||
22 | + } | ||
23 | + proposalsScroll(); | ||
24 | + | ||
25 | + $('.proposals_list .filters a.order').on('ajax:success', function(event, data, status, xhr) { | ||
26 | + $('.proposals_list .filters a.order').removeClass('selected'); | ||
27 | + $(this).addClass('selected'); | ||
28 | + $(this).parents('div.proposals_list').find('.proposals').html(data); | ||
29 | + proposalsScroll(); | ||
30 | + }); | ||
31 | +}); |
@@ -0,0 +1,124 @@ | @@ -0,0 +1,124 @@ | ||
1 | +.private-proposals .proposal { | ||
2 | + background: url(/images/hachure.png); | ||
3 | + opacity: 0.5; | ||
4 | + filter: alpha(opacity=25); | ||
5 | + zoom: 1; | ||
6 | +} | ||
7 | + | ||
8 | +.proposal { | ||
9 | + background: rgb(236, 236, 236); | ||
10 | + width: 100%; | ||
11 | + min-width: 272px; | ||
12 | + vertical-align: top; | ||
13 | + margin: 12px 13px 12px 0; | ||
14 | + box-shadow: 5px 5px 5px -2px #ddd; | ||
15 | + height: 100px; | ||
16 | +} | ||
17 | + | ||
18 | +.article-body-proposals-discussion-plugin_discussion .actions, | ||
19 | +.article-body-proposals-discussion-plugin_topic .actions { | ||
20 | + margin: 10px 0 25px 0; | ||
21 | +} | ||
22 | + | ||
23 | +.proposal .content, .proposal .score, .proposal .topic { | ||
24 | + display: table-cell; | ||
25 | + border-right: 1px solid; | ||
26 | + border-color: rgb(201, 201, 201); | ||
27 | + padding: 5px; | ||
28 | + vertical-align: middle; | ||
29 | + height: 100%; | ||
30 | +} | ||
31 | +.proposal .topic { | ||
32 | + border-right: 0; | ||
33 | + text-align: center; | ||
34 | + width: 24%; | ||
35 | +} | ||
36 | +.proposal .score { | ||
37 | + width: 8%; | ||
38 | + text-align: center; | ||
39 | +} | ||
40 | + | ||
41 | +.proposal .content:hover, .proposal .topic:hover { | ||
42 | + background: rgba(0, 0, 0, 0.1); | ||
43 | +} | ||
44 | + | ||
45 | +.proposal .title { | ||
46 | + font-weight: bold; | ||
47 | + font-size: 15px; | ||
48 | +} | ||
49 | + | ||
50 | +#article .proposal a:visited, #article .proposal a { | ||
51 | + color: rgb(70, 70, 70); | ||
52 | + text-decoration: none; | ||
53 | + width: 100%; | ||
54 | + display: inline-block; | ||
55 | +} | ||
56 | + | ||
57 | +#article .proposal .title a { | ||
58 | + padding: 4px 0px; | ||
59 | +} | ||
60 | + | ||
61 | +.proposal .content { | ||
62 | + width: 68%; | ||
63 | + color: rgb(83, 83, 83); | ||
64 | + vertical-align: top; | ||
65 | + height: 90px; | ||
66 | +} | ||
67 | + | ||
68 | +.proposal .abstract { | ||
69 | + padding-top: 4px; | ||
70 | +} | ||
71 | + | ||
72 | +form .proposals-discussion-plugin textarea { | ||
73 | + width: 98%; | ||
74 | +} | ||
75 | + | ||
76 | +form .proposals-discussion-plugin .abstract textarea { | ||
77 | + height: 60px; | ||
78 | +} | ||
79 | + | ||
80 | +form .proposals-discussion-plugin .body textarea { | ||
81 | + height: 400px; | ||
82 | +} | ||
83 | + | ||
84 | +.topic-color { | ||
85 | + width: 9px; | ||
86 | + float: left; | ||
87 | + height: 100%; | ||
88 | +} | ||
89 | + | ||
90 | +.topics .topic { | ||
91 | + background-color: rgb(233, 233, 233); | ||
92 | + margin: 5px 0; | ||
93 | + height: 25px; | ||
94 | +} | ||
95 | + | ||
96 | +#article .proposal .topic a { | ||
97 | + font-weight: bold; | ||
98 | + color: #888a85; | ||
99 | + width: 100%; | ||
100 | + height: 100%; | ||
101 | +} | ||
102 | + | ||
103 | +#article .topics .topic a { | ||
104 | + text-decoration: none; | ||
105 | + display: inline-block; | ||
106 | + width: 95%; | ||
107 | + height: 100%; | ||
108 | + padding-left: 5px; | ||
109 | + font-weight: bold; | ||
110 | + font-size: 14px; | ||
111 | +} | ||
112 | + | ||
113 | +.proposals_list .filters { | ||
114 | + float: right; | ||
115 | +} | ||
116 | +#article .proposals_list .filters a { | ||
117 | + text-decoration: none; | ||
118 | + border-left: 1px solid rgb(185, 185, 185); | ||
119 | + padding: 0 5px; | ||
120 | + color: #555753; | ||
121 | +} | ||
122 | +.proposals_list .filters a.selected { | ||
123 | + font-weight: bold; | ||
124 | +} |
plugins/proposals_discussion/test/functional/proposals_discussion_plugin_myprofile_controller_test.rb
0 → 100644
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class ProposalsDiscussionPluginMyprofileControllerTest < ActionController::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = fast_create(Community) | ||
7 | + @discussion = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | ||
8 | + @topic = fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => @discussion.id, :profile_id => @profile.id) | ||
9 | + @person = create_user_with_permission('testinguser', 'post_content') | ||
10 | + login_as :testinguser | ||
11 | + end | ||
12 | + | ||
13 | + attr_reader :profile, :discussion, :topic, :person | ||
14 | + | ||
15 | + should 'list topics for selection' do | ||
16 | + 3.times {fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => discussion.id, :profile_id => profile.id)} | ||
17 | + get :select_topic, :profile => profile.identifier, :parent_id => discussion.id | ||
18 | + assert_equal discussion, assigns(:discussion) | ||
19 | + assert_select 'div#topics' do | ||
20 | + assert_select 'div.content', discussion.topics.count | ||
21 | + assert_select "input[name='discussion[topic]']", discussion.topics.count | ||
22 | + end | ||
23 | + assert_tag :form, :attributes => {:action => "/myprofile/#{profile.identifier}/plugin/proposals_discussion/myprofile/new_proposal"} | ||
24 | + end | ||
25 | + | ||
26 | + should 'new_proposal redirect to cms controller' do | ||
27 | + get :new_proposal, :profile => profile.identifier, :discussion => {:topic => topic.id} | ||
28 | + assert_redirected_to :controller => 'cms', :action => 'new', :type => "ProposalsDiscussionPlugin::Proposal", :parent_id => topic.id | ||
29 | + end | ||
30 | + | ||
31 | + should 'publish a proposal' do | ||
32 | + proposal = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :profile_id => profile.id, :published => false, :created_by_id => person.id) | ||
33 | + get :publish_proposal, :proposal_id => proposal.id, :profile => profile.identifier | ||
34 | + assert proposal.reload.published | ||
35 | + end | ||
36 | + | ||
37 | + should 'do not publish if the logged user do not have edition permission' do | ||
38 | + proposal = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :profile_id => profile.id, :published => false) | ||
39 | + get :publish_proposal, :proposal_id => proposal.id, :profile => profile.identifier | ||
40 | + assert_response 403 | ||
41 | + assert !proposal.reload.published | ||
42 | + end | ||
43 | + | ||
44 | +end |
plugins/proposals_discussion/test/functional/proposals_discussion_plugin_public_controller_test.rb
0 → 100644
@@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class ProposalsDiscussionPluginPublicControllerTest < ActionController::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = fast_create(Community) | ||
7 | + @discussion = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | ||
8 | + @topic = fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => @discussion.id, :profile_id => @profile.id) | ||
9 | + end | ||
10 | + | ||
11 | + attr_reader :profile, :discussion, :topic | ||
12 | + | ||
13 | + should 'load proposals' do | ||
14 | + proposals = 3.times.map { fast_create(ProposalsDiscussionPlugin::Proposal, :name => 'proposal title', :abstract => 'proposal abstract', :profile_id => profile.id, :parent_id => topic.id)} | ||
15 | + get :load_proposals, :profile => profile.identifier, :holder_id => discussion.id | ||
16 | + assert_equivalent proposals, assigns(:proposals) | ||
17 | + end | ||
18 | + | ||
19 | + should 'add link to next page' do | ||
20 | + proposal = fast_create(ProposalsDiscussionPlugin::Proposal, :name => 'proposal title', :abstract => 'proposal abstract', :profile_id => profile.id, :parent_id => topic.id) | ||
21 | + get :load_proposals, :profile => profile.identifier, :holder_id => discussion.id | ||
22 | + assert_match /href=.*page=2/, response.body | ||
23 | + end | ||
24 | + | ||
25 | + should 'render blank text if it is the last page' do | ||
26 | + get :load_proposals, :profile => profile.identifier, :holder_id => discussion.id | ||
27 | + assert_equal '', response.body | ||
28 | + end | ||
29 | + | ||
30 | + should 'load proposals with alphabetical order' do | ||
31 | + proposal1 = fast_create(ProposalsDiscussionPlugin::Proposal, :name => 'z proposal', :abstract => 'proposal abstract', :profile_id => profile.id, :parent_id => topic.id) | ||
32 | + proposal2 = fast_create(ProposalsDiscussionPlugin::Proposal, :name => 'abc proposal', :abstract => 'proposal abstract', :profile_id => profile.id, :parent_id => topic.id) | ||
33 | + proposal3 = fast_create(ProposalsDiscussionPlugin::Proposal, :name => 'abd proposal', :abstract => 'proposal abstract', :profile_id => profile.id, :parent_id => topic.id) | ||
34 | + get :load_proposals, :profile => profile.identifier, :holder_id => discussion.id, :order => 'alphabetical' | ||
35 | + assert_equal [proposal2, proposal3, proposal1], assigns(:proposals) | ||
36 | + end | ||
37 | + | ||
38 | +end |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../test/test_helper' |
plugins/proposals_discussion/test/unit/discussion_test.rb
0 → 100644
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class DiscussionTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = fast_create(Community) | ||
7 | + @discussion = ProposalsDiscussionPlugin::Discussion.new(:name => 'test', :profile => @profile) | ||
8 | + end | ||
9 | + | ||
10 | + attr_reader :profile, :discussion | ||
11 | + | ||
12 | + should 'return list of topics' do | ||
13 | + discussion.save! | ||
14 | + topic1 = fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => discussion.id) | ||
15 | + topic2 = fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => discussion.id) | ||
16 | + assert_equivalent [topic1, topic2], discussion.topics | ||
17 | + end | ||
18 | + | ||
19 | + should 'return list of proposals' do | ||
20 | + discussion.save! | ||
21 | + topic = fast_create(ProposalsDiscussionPlugin::Topic, :parent_id => discussion.id) | ||
22 | + proposal1 = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) | ||
23 | + proposal2 = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) | ||
24 | + assert_equivalent [proposal1, proposal2], discussion.proposals | ||
25 | + end | ||
26 | + | ||
27 | +end |
@@ -0,0 +1,32 @@ | @@ -0,0 +1,32 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class ProposalTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = fast_create(Community) | ||
7 | + @person = fast_create(Person) | ||
8 | + @proposal = ProposalsDiscussionPlugin::Proposal.new(:name => 'test', :profile => @profile) | ||
9 | + @proposal.created_by = @person | ||
10 | + end | ||
11 | + | ||
12 | + attr_reader :profile, :proposal, :person | ||
13 | + | ||
14 | + should 'save a proposal' do | ||
15 | + proposal.abstract = 'abstract' | ||
16 | + assert proposal.save | ||
17 | + end | ||
18 | + | ||
19 | + should 'do not save a proposal without abstract' do | ||
20 | + proposal.save | ||
21 | + assert proposal.errors['abstract'].present? | ||
22 | + end | ||
23 | + | ||
24 | + should 'allow edition if user is the author' do | ||
25 | + assert proposal.allow_edit?(person) | ||
26 | + end | ||
27 | + | ||
28 | + should 'do not allow edition if user is not the author' do | ||
29 | + assert !proposal.allow_edit?(fast_create(Person)) | ||
30 | + end | ||
31 | + | ||
32 | +end |
plugins/proposals_discussion/test/unit/proposals_discussion_plugin_test.rb
0 → 100644
@@ -0,0 +1,76 @@ | @@ -0,0 +1,76 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class ProposalsDiscussionPluginTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @plugin = ProposalsDiscussionPlugin.new | ||
7 | + @profile = fast_create(Community) | ||
8 | + @params = {} | ||
9 | + @plugin.stubs(:context).returns(self) | ||
10 | + end | ||
11 | + | ||
12 | + attr_reader :plugin, :profile, :params | ||
13 | + | ||
14 | + should 'has stylesheet' do | ||
15 | + assert @plugin.stylesheet? | ||
16 | + end | ||
17 | + | ||
18 | + should 'return Discussion as a content type' do | ||
19 | + @params[:parent_id] = nil | ||
20 | + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion | ||
21 | + end | ||
22 | + | ||
23 | + should 'do not return Discussion as a content type if it has a parent' do | ||
24 | + parent = fast_create(Folder, :profile_id => @profile.id) | ||
25 | + @params[:parent_id] = parent.id | ||
26 | + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Discussion | ||
27 | + end | ||
28 | + | ||
29 | + should 'return Topic as a content type if parent is a Discussion' do | ||
30 | + parent = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | ||
31 | + @params[:parent_id] = parent.id | ||
32 | + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Topic | ||
33 | + end | ||
34 | + | ||
35 | + should 'return Proposal as a content type if parent is a Topic' do | ||
36 | + parent = fast_create(ProposalsDiscussionPlugin::Topic, :profile_id => @profile.id) | ||
37 | + @params[:parent_id] = parent.id | ||
38 | + assert_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal | ||
39 | + end | ||
40 | + | ||
41 | + should 'do not return Proposal as a content type if parent is nil' do | ||
42 | + @params[:parent_id] = nil | ||
43 | + assert_not_includes plugin.content_types, ProposalsDiscussionPlugin::Proposal | ||
44 | + end | ||
45 | + | ||
46 | + should 'remove new button from content page for a discussion' do | ||
47 | + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | ||
48 | + assert plugin.content_remove_new(page) | ||
49 | + end | ||
50 | + | ||
51 | + should 'remove upload button from content page for a discussion' do | ||
52 | + page = fast_create(ProposalsDiscussionPlugin::Discussion, :profile_id => @profile.id) | ||
53 | + assert plugin.content_remove_upload(page) | ||
54 | + end | ||
55 | + | ||
56 | + should 'remove new button from content page for a proposal' do | ||
57 | + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) | ||
58 | + assert plugin.content_remove_new(page) | ||
59 | + end | ||
60 | + | ||
61 | + should 'remove upload button from content page for a proposal' do | ||
62 | + page = fast_create(ProposalsDiscussionPlugin::Proposal, :profile_id => @profile.id) | ||
63 | + assert plugin.content_remove_upload(page) | ||
64 | + end | ||
65 | + | ||
66 | + should 'do not remove new button from content page for others article types' do | ||
67 | + page = fast_create(Article, :profile_id => @profile.id) | ||
68 | + assert !plugin.content_remove_new(page) | ||
69 | + end | ||
70 | + | ||
71 | + should 'do not remove upload button from content page for others article types' do | ||
72 | + page = fast_create(Article, :profile_id => @profile.id) | ||
73 | + assert !plugin.content_remove_upload(page) | ||
74 | + end | ||
75 | + | ||
76 | +end |
@@ -0,0 +1,50 @@ | @@ -0,0 +1,50 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class TopicTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = fast_create(Community) | ||
7 | + @topic = ProposalsDiscussionPlugin::Topic.new(:name => 'test', :profile => @profile) | ||
8 | + end | ||
9 | + | ||
10 | + attr_reader :profile, :topic | ||
11 | + | ||
12 | + should 'return list of proposals' do | ||
13 | + topic.save! | ||
14 | + proposal1 = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) | ||
15 | + proposal2 = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) | ||
16 | + assert_equivalent [proposal1, proposal2], topic.proposals | ||
17 | + end | ||
18 | + | ||
19 | + should 'allow any user to create proposals in a topic' do | ||
20 | + assert topic.allow_create?(Person.new) | ||
21 | + end | ||
22 | + | ||
23 | + should 'return list of comments' do | ||
24 | + topic.save! | ||
25 | + proposal = fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id) | ||
26 | + comment1 = fast_create(Comment, :source_id => proposal.id) | ||
27 | + comment2 = fast_create(Comment, :source_id => proposal.id) | ||
28 | + assert_equivalent [comment1, comment2], topic.proposals_comments | ||
29 | + end | ||
30 | + | ||
31 | + should 'return list of authors' do | ||
32 | + topic.save! | ||
33 | + author1 = fast_create(Person) | ||
34 | + author2 = fast_create(Person) | ||
35 | + fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :created_by_id => author1) | ||
36 | + fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :created_by_id => author2) | ||
37 | + assert_equivalent [author1, author2], topic.proposals_authors | ||
38 | + end | ||
39 | + | ||
40 | + should 'return most active participants' do | ||
41 | + topic.save! | ||
42 | + author1 = fast_create(Person) | ||
43 | + author2 = fast_create(Person) | ||
44 | + fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :created_by_id => author1) | ||
45 | + fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :created_by_id => author2) | ||
46 | + fast_create(ProposalsDiscussionPlugin::Proposal, :parent_id => topic.id, :created_by_id => author2) | ||
47 | + assert_equal [author2, author1], topic.most_active_participants | ||
48 | + end | ||
49 | + | ||
50 | +end |
plugins/proposals_discussion/views/cms/proposals_discussion_plugin/_proposal.html.erb
0 → 100644
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +<%= required_fields_message %> | ||
2 | + | ||
3 | +<%= render :file => 'shared/tiny_mce' %> | ||
4 | + | ||
5 | +<% title_limit = 70 %> | ||
6 | +<% abstract_limit = 140 %> | ||
7 | + | ||
8 | +<div class="proposals-discussion-plugin"> | ||
9 | + <div class="title"> | ||
10 | + <%= required labelled_form_field _('Title'), limited_text_area(:article, :name, title_limit, 'title_textarea', :rows => 1) %> | ||
11 | + </div> | ||
12 | + | ||
13 | + <div class="abstract"> | ||
14 | + <%= required labelled_form_field _('Abstract'), limited_text_area(:article, :abstract, abstract_limit, 'abstract_textarea') %> | ||
15 | + </div> | ||
16 | + | ||
17 | + <div class="body"> | ||
18 | + <% editor_type = 'mceEditor' %> | ||
19 | + <%= labelled_form_field(_('Text'), text_area(:article, :body, :class => editor_type)) %> | ||
20 | + </div> | ||
21 | +</div> | ||
22 | + | ||
23 | +<script> | ||
24 | +jQuery( document ).ready(function( $ ) { | ||
25 | + limited_text_area('title_textarea', <%= title_limit %>); | ||
26 | + limited_text_area('abstract_textarea', <%= abstract_limit %>); | ||
27 | +}); | ||
28 | +</script> |
plugins/proposals_discussion/views/cms/proposals_discussion_plugin/_topic.html.erb
0 → 100644
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +<%= stylesheet_link_tag 'spectrum.css' %> | ||
2 | +<%= javascript_include_tag "spectrum.js" %> | ||
3 | +<%= javascript_include_tag "colorpicker-noosfero.js" %> | ||
4 | + | ||
5 | +<%= required_fields_message %> | ||
6 | + | ||
7 | +<%= required f.text_field('name', :size => '64', :maxlength => 150) %> | ||
8 | +<%= render :partial => 'general_fields' %> | ||
9 | + | ||
10 | +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %> | ||
11 | + | ||
12 | +<%= labelled_colorpicker_field(_('Color:'), :article, :color) %> | ||
13 | +<span id="color_preview" class = "color_marker" style="background-color: <%= @article.color %>" ></span> |
plugins/proposals_discussion/views/content_viewer/_proposal_card.html.erb
0 → 100644
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +<div class="proposal"> | ||
2 | + <div class="topic-color" style="background-color: <%= proposal_card.topic.color %>;"></div> | ||
3 | + <div class="content"> | ||
4 | + <div class="title"> | ||
5 | + <%= link_to proposal_card.name, proposal_card.view_url %> | ||
6 | + </div> | ||
7 | + <div class="social"> | ||
8 | + <%= render :partial => 'content_viewer/social', :locals => {:proposal => proposal_card} %> | ||
9 | + </div> | ||
10 | + <div class="abstract"> | ||
11 | + <%= link_to strip_tags(proposal_card.abstract), proposal_card.view_url %> | ||
12 | + </div> | ||
13 | + </div> | ||
14 | + <div class="score"> | ||
15 | + <%= proposal_card.comments_count %> | ||
16 | + </div> | ||
17 | + <div class="topic"> | ||
18 | + <%= link_to proposal_card.topic.title, proposal_card.topic.view_url %> | ||
19 | + </div> | ||
20 | +</div> |
plugins/proposals_discussion/views/content_viewer/_proposals_list.html.erb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +<script src="/javascripts/plugins/proposals_discussion/jquery.jscroll.min.js" type="text/javascript"></script> | ||
2 | +<%= javascript_include_tag 'plugins/proposals_discussion/proposals_list.js' %> | ||
3 | + | ||
4 | +<% extend ProposalsDiscussionPlugin::ProposalsListHelper %> | ||
5 | + | ||
6 | +<% private_proposals = user ? @page.proposals.private(user) : [] %> | ||
7 | +<% unless private_proposals.empty? %> | ||
8 | +<div class="private-proposals"> | ||
9 | + <h5><%= _('My private proposals') %></h5> | ||
10 | + <%= render :partial => 'content_viewer/proposal_card', :collection => private_proposals %> | ||
11 | +</div> | ||
12 | +<% end %> | ||
13 | + | ||
14 | +<% order ||= 'random' %> | ||
15 | +<div class="proposals_list"> | ||
16 | + <h5><%= _('Proposals') %></h5> | ||
17 | + <div class="filters"> | ||
18 | + <% [[_('Random'), :random], [_('Aplhabetical'), :alphabetical]].each_with_index do |order, i| %> | ||
19 | + <%= link_to order.first, url_for({:controller => 'proposals_discussion_plugin_public', :action => 'load_proposals', :holder_id => holder.id, :profile => profile.identifier, :order => order.second}), :remote => true, :class => "order #{order.second} #{i==0 ? 'selected':''}" %> | ||
20 | + <% end %> | ||
21 | + </div> | ||
22 | + <div class="clear"></div> | ||
23 | + | ||
24 | + <div class="proposals"> | ||
25 | + <div class="more"> | ||
26 | + <img src="/images/loading.gif" alt="Loading" /><%= _("Loading...") %> | ||
27 | + <%= more_proposals('', holder, order) %> | ||
28 | + </div> | ||
29 | + </div> | ||
30 | +</div> |
plugins/proposals_discussion/views/content_viewer/_proposals_list_content.html.erb
0 → 100644
plugins/proposals_discussion/views/content_viewer/_social.html.erb
0 → 100644
plugins/proposals_discussion/views/content_viewer/discussion.html.erb
0 → 100644
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +<div class="description"> | ||
2 | + <%= @page.body %> | ||
3 | +</div> | ||
4 | + | ||
5 | +<% if @page.allow_create?(user) %> | ||
6 | +<div class="actions"> | ||
7 | + <%= link_to url_for({:controller => 'cms', :action => 'new', :type => "ProposalsDiscussionPlugin::Topic", :parent_id => @page.id}), :class => 'button with-text icon-add' do %> | ||
8 | + <strong><%= _("New Topic") %></strong> | ||
9 | + <% end %> | ||
10 | +</div> | ||
11 | +<% end %> | ||
12 | + | ||
13 | +<div class="topics"> | ||
14 | + <h3><%= _('Discussion Topics') %></h3> | ||
15 | + <% @page.topics.includes(:profile).each do |topic| %> | ||
16 | + <div class="topic"> | ||
17 | + <div class="topic-color" style="background-color: <%= topic.color %>;"></div> | ||
18 | + <%= link_to topic.title, topic.view_url %> | ||
19 | + </div> | ||
20 | + <% end %> | ||
21 | +</div> | ||
22 | + | ||
23 | +<div class="actions"> | ||
24 | + <%= link_to url_for({:controller => 'proposals_discussion_plugin_myprofile', :action => 'select_topic', :parent_id => @page.id}), :class => 'button with-text icon-add' do %> | ||
25 | + <strong><%= _("Send my proposal") %></strong> | ||
26 | + <% end %> | ||
27 | +</div> | ||
28 | + | ||
29 | +<%= render :partial => 'content_viewer/proposals_list', :locals => {:holder => @page} %> |
plugins/proposals_discussion/views/content_viewer/proposal.html.erb
0 → 100644
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +<div class="topic"> | ||
2 | + <h5><%= _('Discussion Topic') %></h5> | ||
3 | + <div class="content"><%= @page.topic.title %></div> | ||
4 | +</div> | ||
5 | + | ||
6 | +<div class="title"> | ||
7 | + <h5><%= _('Title') %></h4> | ||
8 | + <div class="content"><%= @page.title %></div> | ||
9 | +</div> | ||
10 | + | ||
11 | +<div class="abstract"> | ||
12 | + <h5><%= _('Abstract') %></h4> | ||
13 | + <div class="content"><%= @page.abstract %></div> | ||
14 | +</div> | ||
15 | + | ||
16 | +<div class="body"> | ||
17 | + <h5><%= _('Body') %></h4> | ||
18 | + <div class="content"><%= @page.body %></div> | ||
19 | +</div> | ||
20 | + | ||
21 | +<% if @page.allow_edit?(user) && !@page.published %> | ||
22 | +<div class="actions"> | ||
23 | + <%= link_to url_for({:controller => 'proposals_discussion_plugin_myprofile', :action => 'publish_proposal', :proposal_id => @page.id}), :class => 'button with-text icon-suggest' do %> | ||
24 | + <strong><%= _("Publish") %></strong> | ||
25 | + <% end %> | ||
26 | +</div> | ||
27 | +<% end %> |
plugins/proposals_discussion/views/content_viewer/topic.html.erb
0 → 100644
@@ -0,0 +1,33 @@ | @@ -0,0 +1,33 @@ | ||
1 | +<div class="description"> | ||
2 | + <%= @page.body %> | ||
3 | +</div> | ||
4 | +<h4><%= @page.discussion.title %></h4> | ||
5 | + | ||
6 | +<div class="proposals-count"> | ||
7 | + <span class="label"><%= _('Number of Proposals: ') %></span> | ||
8 | + <span class="content"><%= @page.proposals.count %></span> | ||
9 | +</div> | ||
10 | +<div class="participants-count"> | ||
11 | + <span class="label"><%= _('Number of Participants: ') %></span> | ||
12 | + <span class="content"><%= @page.proposals_authors.count %></span> | ||
13 | +</div> | ||
14 | +<div class="comments-count"> | ||
15 | + <span class="label"><%= _('Number of Comments: ') %></span> | ||
16 | + <span class="content"><%= @page.proposals_comments.count %></span> | ||
17 | +</div> | ||
18 | +<div class="active-participants"> | ||
19 | + <span class="label"><%= _('Most active: ') %></span> | ||
20 | + <span class="content"> | ||
21 | + <% @page.most_active_participants.each do |author| %> | ||
22 | + <%= link_to profile_image(author, :icon), author.url, :title => author.name %> | ||
23 | + <% end %> | ||
24 | + </span> | ||
25 | +</div> | ||
26 | + | ||
27 | +<div class="actions"> | ||
28 | + <%= link_to url_for({:controller => 'cms', :action => 'new', :type => "ProposalsDiscussionPlugin::Proposal", :parent_id => @page.id}), :class => 'button with-text icon-add' do %> | ||
29 | + <strong><%= _("Send my proposal") %></strong> | ||
30 | + <% end %> | ||
31 | +</div> | ||
32 | + | ||
33 | +<%= render :partial => 'content_viewer/proposals_list', :locals => {:holder => @page} %> |
plugins/proposals_discussion/views/select_topic.html.erb
0 → 100644
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +<script> | ||
2 | + jQuery(document).ready(function($){ | ||
3 | + $("#topics").accordion(); | ||
4 | + $('#topics input[type=radio],label').on('click',function(e){e.stopPropagation();}); | ||
5 | + $('#topics h4').click(function(e){ | ||
6 | + e.stopPropagation(); | ||
7 | + $(this).find('input:radio').prop('checked', true); | ||
8 | + }); | ||
9 | + }); | ||
10 | +</script> | ||
11 | + | ||
12 | +<div class="proposals-discussion-plugin select-topic"> | ||
13 | + <h1><%= @discussion.title %></h1> | ||
14 | + <%= form_for :discussion, :url => {:controller => 'proposals_discussion_plugin_myprofile', :action => 'new_proposal'} do %> | ||
15 | + | ||
16 | + <h3><%= _('Select topic') %></h3> | ||
17 | + <div id="topics"> | ||
18 | + | ||
19 | + <% @discussion.children.each do |topic| %> | ||
20 | + <h4> | ||
21 | + <%= radio_button_tag('discussion[topic]', topic.id) %> | ||
22 | + <%= topic.title %> | ||
23 | + </h4> | ||
24 | + <div class="content"> | ||
25 | + <%= topic.body %> | ||
26 | + </div> | ||
27 | + <% end %> | ||
28 | + | ||
29 | + <div class="clear"></div> | ||
30 | + </div> | ||
31 | + | ||
32 | + <div class="actions"> | ||
33 | + <%= submit_button(:next, _('Next')) %> | ||
34 | + <%= button :cancel, _('Cancel'), @discussion.view_url %> | ||
35 | + </div> | ||
36 | + <% end %> | ||
37 | +</div> |
test/functional/features_controller_test.rb
@@ -146,7 +146,7 @@ class FeaturesControllerTest < ActionController::TestCase | @@ -146,7 +146,7 @@ class FeaturesControllerTest < ActionController::TestCase | ||
146 | assert_equal true, e.custom_community_fields['contact_person']['required'] | 146 | assert_equal true, e.custom_community_fields['contact_person']['required'] |
147 | end | 147 | end |
148 | 148 | ||
149 | - should 'search members' do | 149 | + should 'search members by name' do |
150 | uses_host 'anhetegua.net' | 150 | uses_host 'anhetegua.net' |
151 | person = fast_create(Person, :environment_id => Environment.find(2).id) | 151 | person = fast_create(Person, :environment_id => Environment.find(2).id) |
152 | xhr :get, :search_members, :q => person.name[0..2] | 152 | xhr :get, :search_members, :q => person.name[0..2] |
@@ -154,4 +154,12 @@ class FeaturesControllerTest < ActionController::TestCase | @@ -154,4 +154,12 @@ class FeaturesControllerTest < ActionController::TestCase | ||
154 | assert_includes json_response, {"id"=>person.id, "name"=>person.name} | 154 | assert_includes json_response, {"id"=>person.id, "name"=>person.name} |
155 | end | 155 | end |
156 | 156 | ||
157 | + should 'search members by identifier' do | ||
158 | + uses_host 'anhetegua.net' | ||
159 | + person = fast_create(Person, :name => 'Some Name', :identifier => 'person-identifier', :environment_id => Environment.find(2).id) | ||
160 | + xhr :get, :search_members, :q => person.identifier | ||
161 | + json_response = ActiveSupport::JSON.decode(@response.body) | ||
162 | + assert_includes json_response, {"id"=>person.id, "name"=>person.name} | ||
163 | + end | ||
164 | + | ||
157 | end | 165 | end |
test/unit/categories_helper_test.rb
@@ -31,4 +31,10 @@ class CategoriesHelperTest < ActiveSupport::TestCase | @@ -31,4 +31,10 @@ class CategoriesHelperTest < ActiveSupport::TestCase | ||
31 | assert_equal '', category_color_style(category2) | 31 | assert_equal '', category_color_style(category2) |
32 | end | 32 | end |
33 | 33 | ||
34 | + should 'not return category parent color if category is nil' do | ||
35 | + assert_nothing_raised do | ||
36 | + assert_equal '', category_color_style(nil) | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
34 | end | 40 | end |