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 | 93 | |
94 | 94 | def search_members |
95 | 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 | 97 | render :text => prepare_to_token_input(result).to_json |
98 | 98 | end |
99 | 99 | ... | ... |
app/helpers/categories_helper.rb
app/models/article.rb
... | ... | @@ -252,7 +252,7 @@ class Article < ActiveRecord::Base |
252 | 252 | } |
253 | 253 | |
254 | 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 | 257 | scope :more_recent, |
258 | 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 | 11 | |
12 | 12 | module WithinHelpers |
13 | 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 | 22 | end |
17 | 23 | end |
18 | 24 | World(WithinHelpers) | ... | ... |
plugins/proposals_discussion/controllers/myprofile/proposals_discussion_plugin_myprofile_controller.rb
0 → 100644
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 16 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
1 | +require File.dirname(__FILE__) + '/../../../test/test_helper' | ... | ... |
plugins/proposals_discussion/test/unit/discussion_test.rb
0 → 100644
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 146 | assert_equal true, e.custom_community_fields['contact_person']['required'] |
147 | 147 | end |
148 | 148 | |
149 | - should 'search members' do | |
149 | + should 'search members by name' do | |
150 | 150 | uses_host 'anhetegua.net' |
151 | 151 | person = fast_create(Person, :environment_id => Environment.find(2).id) |
152 | 152 | xhr :get, :search_members, :q => person.name[0..2] |
... | ... | @@ -154,4 +154,12 @@ class FeaturesControllerTest < ActionController::TestCase |
154 | 154 | assert_includes json_response, {"id"=>person.id, "name"=>person.name} |
155 | 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 | 165 | end | ... | ... |
test/unit/categories_helper_test.rb
... | ... | @@ -31,4 +31,10 @@ class CategoriesHelperTest < ActiveSupport::TestCase |
31 | 31 | assert_equal '', category_color_style(category2) |
32 | 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 | 40 | end | ... | ... |