Commit fc8557c3c6c62a489bab035ea63f3ee7a10c5db0

Authored by Daniela Feitosa
2 parents 5fb09b51 85b0bd4d

Merge commit 'refs/merge-requests/213' of git://gitorious.org/noosfero/noosfero …

…into merge-requests/213

Conflicts:
	app/controllers/application_controller.rb
	app/helpers/application_helper.rb
	app/views/content_viewer/_comment.rhtml
	app/views/content_viewer/view_page.rhtml
	lib/noosfero/plugin.rb
	test/functional/content_viewer_controller_test.rb
	test/unit/comment_test.rb
Showing 38 changed files with 650 additions and 68 deletions   Show diff stats
app/controllers/application_controller.rb
@@ -114,7 +114,9 @@ class ApplicationController < ActionController::Base @@ -114,7 +114,9 @@ class ApplicationController < ActionController::Base
114 # plugin to the current controller being initialized. 114 # plugin to the current controller being initialized.
115 def init_noosfero_plugins_controller_filters 115 def init_noosfero_plugins_controller_filters
116 plugins.each do |plugin| 116 plugins.each do |plugin|
117 - plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| 117 + filters = plugin.send(self.class.name.underscore + '_filters')
  118 + filters = [filters] if !filters.kind_of?(Array)
  119 + filters.each do |plugin_filter|
118 self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) 120 self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {}))
119 self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) 121 self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block])
120 end 122 end
app/controllers/public/content_viewer_controller.rb
@@ -2,6 +2,8 @@ class ContentViewerController < ApplicationController @@ -2,6 +2,8 @@ class ContentViewerController < ApplicationController
2 2
3 needs_profile 3 needs_profile
4 4
  5 + before_filter :comment_author, :only => :edit_comment
  6 +
5 helper ProfileHelper 7 helper ProfileHelper
6 helper TagsHelper 8 helper TagsHelper
7 9
@@ -121,6 +123,22 @@ class ContentViewerController < ApplicationController @@ -121,6 +123,22 @@ class ContentViewerController < ApplicationController
121 end 123 end
122 end 124 end
123 125
  126 + def edit_comment
  127 + path = params[:page].join('/')
  128 + @page = profile.articles.find_by_path(path)
  129 + @form_div = 'opened'
  130 + @comment = Comment.find(params[:id])
  131 + if request.post?
  132 + begin
  133 + @comment.update_attributes(params[:comment])
  134 + session[:notice] = _('Comment updated.')
  135 + redirect_to :action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path
  136 + rescue
  137 + session[:notice] = _('Comment could not be updated.')
  138 + end
  139 + end
  140 + end
  141 +
124 protected 142 protected
125 143
126 def add_comment 144 def add_comment
@@ -198,4 +216,9 @@ class ContentViewerController < ApplicationController @@ -198,4 +216,9 @@ class ContentViewerController < ApplicationController
198 end 216 end
199 end 217 end
200 218
  219 + def comment_author
  220 + comment = Comment.find(params[:id])
  221 + render_access_denied if comment.author.blank? || comment.author != user
  222 + end
  223 +
201 end 224 end
app/helpers/application_helper.rb
@@ -1336,6 +1336,19 @@ module ApplicationHelper @@ -1336,6 +1336,19 @@ module ApplicationHelper
1336 end 1336 end
1337 end 1337 end
1338 1338
  1339 + def expirable_link_to(expired, content, url, options = {})
  1340 + if expired
  1341 + options[:class] = (options[:class] || '') + ' disabled'
  1342 + content_tag('a', ' '+content_tag('span', content), options)
  1343 + else
  1344 + link_to content, url, options
  1345 + end
  1346 + end
  1347 +
  1348 + def remove_content_button(action)
  1349 + @plugins.dispatch("content_remove_#{action.to_s}", @page).include?(true)
  1350 + end
  1351 +
1339 def template_options(klass, field_name) 1352 def template_options(klass, field_name)
1340 return '' if klass.templates.count == 0 1353 return '' if klass.templates.count == 0
1341 return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1 1354 return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1
@@ -1401,4 +1414,19 @@ module ApplicationHelper @@ -1401,4 +1414,19 @@ module ApplicationHelper
1401 result 1414 result
1402 end 1415 end
1403 1416
  1417 + def expirable_content_reference(content, action, text, url, options = {})
  1418 + reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first
  1419 + options[:title] = reason
  1420 + expirable_link_to reason.present?, text, url, options
  1421 + end
  1422 +
  1423 + def expirable_button(content, action, text, url, options = {})
  1424 + options[:class] = "button with-text icon-#{action.to_s}"
  1425 + expirable_content_reference content, action, text, url, options
  1426 + end
  1427 +
  1428 + def expirable_comment_link(content, action, text, url, options = {})
  1429 + options[:class] = "comment-footer comment-footer-link comment-footer-hide"
  1430 + expirable_content_reference content, action, text, url, options
  1431 + end
1404 end 1432 end
app/helpers/cms_helper.rb
@@ -42,13 +42,25 @@ module CmsHelper @@ -42,13 +42,25 @@ module CmsHelper
42 42
43 def display_spread_button(profile, article) 43 def display_spread_button(profile, article)
44 if profile.person? 44 if profile.person?
45 - button_without_text :spread, _('Spread this'), :action => 'publish', :id => article.id 45 + expirable_button article, :spread, _('Spread this'), :action => 'publish', :id => article.id
46 elsif profile.community? && environment.portal_community 46 elsif profile.community? && environment.portal_community
47 - button_without_text :spread, _('Spread this'), :action => 'publish_on_portal_community', :id => article.id 47 + expirable_button article, :spread, _('Spread this'), :action => 'publish_on_portal_community', :id => article.id
48 end 48 end
49 end 49 end
50 50
51 def display_delete_button(article) 51 def display_delete_button(article)
52 - button_without_text :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => delete_article_message(article) 52 + expirable_button article, :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => delete_article_message(article)
  53 + end
  54 +
  55 + def expirable_button(content, action, title, url, options = {})
  56 + reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first
  57 + if reason.present?
  58 + options[:class] = (options[:class] || '') + ' disabled'
  59 + options[:disabled] = 'disabled'
  60 + options.delete(:confirm)
  61 + options.delete(:method)
  62 + title = reason
  63 + end
  64 + button_without_text action.to_sym, title, url, options
53 end 65 end
54 end 66 end
app/models/comment.rb
@@ -28,6 +28,8 @@ class Comment < ActiveRecord::Base @@ -28,6 +28,8 @@ class Comment < ActiveRecord::Base
28 28
29 xss_terminate :only => [ :body, :title, :name ], :on => 'validation' 29 xss_terminate :only => [ :body, :title, :name ], :on => 'validation'
30 30
  31 + delegate :environment, :to => :source
  32 +
31 def action_tracker_target 33 def action_tracker_target
32 self.article.profile 34 self.article.profile
33 end 35 end
app/views/cms/view.rhtml
@@ -49,13 +49,13 @@ @@ -49,13 +49,13 @@
49 <%= article.class.short_description %> 49 <%= article.class.short_description %>
50 </td> 50 </td>
51 <td class="article-controls"> 51 <td class="article-controls">
52 - <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => article.id %> 52 + <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %>
53 <%= button_without_text :eyes, _('Public view'), article.view_url %> 53 <%= button_without_text :eyes, _('Public view'), article.view_url %>
54 - <%= display_spread_button(profile, article) unless article.folder? %>  
55 - <% if !environment.enabled?('cant_change_homepage') %>  
56 - <%= button_without_text :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> 54 + <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%>
  55 + <% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
  56 + <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
57 <% end %> 57 <% end %>
58 - <%= display_delete_button(article) %> 58 + <%= display_delete_button(article) if !remove_content_button(:delete) %>
59 </td> 59 </td>
60 </tr> 60 </tr>
61 <% end %> 61 <% end %>
app/views/content_viewer/_article_toolbar.rhtml
1 <div<%= user && " class='logged-in'" %>> 1 <div<%= user && " class='logged-in'" %>>
2 <div id="article-actions"> 2 <div id="article-actions">
3 3
4 - <% if @page.allow_edit?(user) %>  
5 - <%= link_to content_tag( 'span', label_for_edit_article(@page) ),  
6 - profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }),  
7 - :class => 'button with-text icon-edit' %> 4 +
  5 + <% if @page.allow_edit?(user) && !remove_content_button(:edit) %>
  6 + <% content = content_tag('span', label_for_edit_article(@page)) %>
  7 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }) %>
  8 + <%= expirable_button @page, :edit, content, url %>
8 <% end %> 9 <% end %>
9 10
10 - <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) %>  
11 - <%= link_to content_tag( 'span', _('Delete') ),  
12 - profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page}),  
13 - :method => :post,  
14 - :class => 'button with-text icon-delete',  
15 - :confirm => delete_article_message(@page) %> 11 + <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) && !remove_content_button(:delete)%>
  12 + <% content = content_tag( 'span', _('Delete') ) %>
  13 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page}) %>
  14 + <% options = {:method => :post, :confirm => delete_article_message(@page)} %>
  15 + <%= expirable_button @page, :delete, content, url, options %>
16 <% end %> 16 <% end %>
17 17
18 - <% if !@page.folder? && @page.allow_spread?(user) %> 18 + <% if !@page.folder? && @page.allow_spread?(user) && !remove_content_button(:spread) %>
  19 + <% content = content_tag( 'span', _('Spread this') ) %>
  20 + <% url = nil %>
19 <% if profile.kind_of?(Person) %> 21 <% if profile.kind_of?(Person) %>
20 - <%= link_to content_tag( 'span', _('Spread this') ),  
21 - profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page }),  
22 - :class => 'button with-text icon-spread' %> 22 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page }) %>
23 <% elsif profile.kind_of?(Community) && environment.portal_community %> 23 <% elsif profile.kind_of?(Community) && environment.portal_community %>
24 - <%= link_to content_tag( 'span', _('Spread this') ),  
25 - profile.admin_url.merge({ :controller => 'cms', :action => 'publish_on_portal_community', :id => @page }),  
26 - :class => 'button with-text icon-spread' %> 24 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish_on_portal_community', :id => @page }) %>
27 <% end %> 25 <% end %>
  26 + <%= expirable_button @page, :spread, content, url if url %>
28 <% end %> 27 <% end %>
29 28
30 <% if !@page.gallery? && @page.allow_create?(user) %> 29 <% if !@page.gallery? && @page.allow_create?(user) %>
31 - <%= link_to _('Add translation'),  
32 - profile.admin_url.merge(:controller => 'cms', :action => 'new',  
33 - :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)),  
34 - :type => @page.type, :article => { :translation_of_id => @page.native_translation.id }),  
35 - :class => 'button with-text icon-locale' if @page.translatable? && !@page.native_translation.language.blank? %> 30 + <% if @page.translatable? && !@page.native_translation.language.blank? && !remove_content_button(:locale) %>
  31 + <% content = _('Add translation') %>
  32 + <% parent_id = (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)) %>
  33 + <% url = profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => parent_id, :type => @page.type, :article => { :translation_of_id => @page.native_translation.id })%>
  34 + <%= expirable_button @page, :locale, content, url %>
  35 + <% end %>
  36 +
36 <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %> 37 <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
37 <% end %> 38 <% end %>
38 39
@@ -40,8 +41,11 @@ @@ -40,8 +41,11 @@
40 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %> 41 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
41 <% end %> 42 <% end %>
42 43
43 - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) %>  
44 - <%= link_to content_tag( 'span', _('Suggest an article') ), profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}), :id => 'suggest-article-link', :class => 'button with-text icon-new' %> 44 + <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %>
  45 + <% content = content_tag( 'span', _('Suggest an article') ) %>
  46 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %>
  47 + <% options = {:id => 'suggest-article-link'} %>
  48 + <%= expirable_button @page, :suggest, content, url, options %>
45 <% end %> 49 <% end %>
46 50
47 <%= report_abuse(profile, :link, @page) %> 51 <%= report_abuse(profile, :link, @page) %>
app/views/content_viewer/_comment.rhtml
@@ -75,6 +75,10 @@ @@ -75,6 +75,10 @@
75 :class => 'comment-footer comment-footer-link comment-footer-hide', 75 :class => 'comment-footer comment-footer-link comment-footer-hide',
76 :id => 'comment-reply-to-' + comment.id.to_s 76 :id => 'comment-reply-to-' + comment.id.to_s
77 %> 77 %>
  78 + <% if comment.author && comment.author == user %>
  79 + &nbsp;
  80 + <%= expirable_comment_link comment, :edit, _('Edit'), {:action => 'edit_comment', :id => comment.id, :profile => profile.identifier} %>
  81 + <% end %>
78 <% end %> 82 <% end %>
79 </div> 83 </div>
80 84
app/views/content_viewer/_comment_form.rhtml
@@ -39,7 +39,7 @@ function submit_comment_form(button) { @@ -39,7 +39,7 @@ function submit_comment_form(button) {
39 d.find('input[name=comment[title]], textarea').val(''); 39 d.find('input[name=comment[title]], textarea').val('');
40 d.find('.comment_form input[name=comment[<%= focus_on %>]]').focus(); 40 d.find('.comment_form input[name=comment[<%= focus_on %>]]').focus();
41 }"> 41 }">
42 - <%= content_tag('a', '', :name => 'comment_form') + _('Post a comment') %> 42 + <%= content_tag('a', '', :name => 'comment_form') + _('Post a comment') if display_link %>
43 </h4> 43 </h4>
44 44
45 <% unless pass_without_comment_captcha? %> 45 <% unless pass_without_comment_captcha? %>
@@ -59,7 +59,7 @@ function submit_comment_form(button) { @@ -59,7 +59,7 @@ function submit_comment_form(button) {
59 </script> 59 </script>
60 <% end %> 60 <% end %>
61 61
62 -<% form_tag( url_for(@page.view_url.merge({:only_path => true})), { :class => 'comment_form' } ) do %> 62 +<% form_tag( url, { :class => 'comment_form' } ) do %>
63 <%= hidden_field_tag(:confirm, 'false') %> 63 <%= hidden_field_tag(:confirm, 'false') %>
64 64
65 <%= required_fields_message %> 65 <%= required_fields_message %>
@@ -84,7 +84,11 @@ function submit_comment_form(button) { @@ -84,7 +84,11 @@ function submit_comment_form(button) {
84 84
85 <% button_bar do %> 85 <% button_bar do %>
86 <%= submit_button('add', _('Post comment'), :onclick => "submit_comment_form(this); return false") %> 86 <%= submit_button('add', _('Post comment'), :onclick => "submit_comment_form(this); return false") %>
87 - <%= button_to_function :cancel, _('Cancel'), "f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %> 87 + <% if cancel_triggers_hide %>
  88 + <%= button_to_function :cancel, _('Cancel'), "f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %>
  89 + <% else %>
  90 + <%= button('cancel', _('Cancel'), {:action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path})%>
  91 + <% end %>
88 <% end %> 92 <% end %>
89 <% end %> 93 <% end %>
90 94
app/views/content_viewer/edit_comment.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1><%= _('Edit comment') %></h1>
  2 +
  3 +<%= render :partial => 'comment_form', :locals => {:url => {:action => 'edit_comment', :profile => profile.identifier}, :display_link => false, :cancel_triggers_hide => false} %>
app/views/content_viewer/view_page.rhtml
@@ -98,7 +98,7 @@ @@ -98,7 +98,7 @@
98 </ul> 98 </ul>
99 99
100 <% if @page.accept_comments? %> 100 <% if @page.accept_comments? %>
101 - <div id="page-comment-form"><%= render :partial => 'comment_form' %></div> 101 + <div id="page-comment-form"><%= render :partial => 'comment_form', :locals => {:url => url_for(@page.view_url.merge({:only_path => true})), :display_link => true, :cancel_triggers_hide => true}%></div>
102 <% end %> 102 <% end %>
103 </div><!-- end class="comments" --> 103 </div><!-- end class="comments" -->
104 104
app/views/profile/_comment.rhtml
@@ -62,6 +62,10 @@ @@ -62,6 +62,10 @@
62 </script> 62 </script>
63 <% end %> 63 <% end %>
64 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %> 64 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>
  65 + <% if comment.author && comment.author == user %>
  66 + <%= expirable_comment_link comment, :edit, _('Edit'), {:action => 'edit_comment', :id => comment.id, :profile => profile.identifier} %>
  67 + <%= content_tag('span', ' | ', :class => 'comment-footer comment-footer-hide') %>
  68 + <% end %>
65 <%= link_to_function _('Reply'), 69 <%= link_to_function _('Reply'),
66 "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id, 70 "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id,
67 :class => 'comment-footer comment-footer-link comment-footer-hide', 71 :class => 'comment-footer comment-footer-link comment-footer-hide',
config/routes.rb
@@ -121,9 +121,12 @@ ActionController::Routing::Routes.draw do |map| @@ -121,9 +121,12 @@ ActionController::Routing::Routes.draw do |map|
121 # cache stuff - hack 121 # cache stuff - hack
122 map.cache 'public/:action/:id', :controller => 'public' 122 map.cache 'public/:action/:id', :controller => 'public'
123 123
  124 + map.connect ':profile/edit_comment/:id/*page', :controller => 'content_viewer', :action => 'edit_comment', :profile => /#{Noosfero.identifier_format}/
  125 +
124 # match requests for profiles that don't have a custom domain 126 # match requests for profiles that don't have a custom domain
125 map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } 127 map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
126 128
  129 +
127 # match requests for content in domains hosted for profiles 130 # match requests for content in domains hosted for profiles
128 map.connect '*page', :controller => 'content_viewer', :action => 'view_page' 131 map.connect '*page', :controller => 'content_viewer', :action => 'view_page'
129 132
lib/noosfero/plugin.rb
@@ -211,28 +211,6 @@ class Noosfero::Plugin @@ -211,28 +211,6 @@ class Noosfero::Plugin
211 nil 211 nil
212 end 212 end
213 213
214 - # This is a generic hotspot for all controllers on Noosfero.  
215 - # If any plugin wants to define filters to run on any controller, the name of  
216 - # the hotspot must be in the following form: <underscored_controller_name>_filters.  
217 - # Example: for ProfileController the hotspot is profile_controller_filters  
218 - #  
219 - # -> Adds a filter to a controller  
220 - # returns = { :type => type,  
221 - # :method_name => method_name,  
222 - # :options => {:opt1 => opt1, :opt2 => opt2},  
223 - # :block => Proc or lambda block}  
224 - # type = 'before_filter' or 'after_filter'  
225 - # method_name = The name of the filter  
226 - # option = Filter options, like :only or :except  
227 - # block = Block that the filter will call  
228 - def method_missing(method, *args, &block)  
229 - if method.to_s =~ /^(.+)_controller_filters$/  
230 - []  
231 - else  
232 - super  
233 - end  
234 - end  
235 -  
236 # This method will be called just before a comment is saved to the database. 214 # This method will be called just before a comment is saved to the database.
237 # 215 #
238 # It can modify the comment in several ways. In special, a plugin can call 216 # It can modify the comment in several ways. In special, a plugin can call
@@ -333,4 +311,40 @@ class Noosfero::Plugin @@ -333,4 +311,40 @@ class Noosfero::Plugin
333 nil 311 nil
334 end 312 end
335 313
  314 + def method_missing(method, *args, &block)
  315 + # This is a generic hotspot for all controllers on Noosfero.
  316 + # If any plugin wants to define filters to run on any controller, the name of
  317 + # the hotspot must be in the following form: <underscored_controller_name>_filters.
  318 + # Example: for ProfileController the hotspot is profile_controller_filters
  319 + #
  320 + # -> Adds a filter to a controller
  321 + # returns = { :type => type,
  322 + # :method_name => method_name,
  323 + # :options => {:opt1 => opt1, :opt2 => opt2},
  324 + # :block => Proc or lambda block}
  325 + # type = 'before_filter' or 'after_filter'
  326 + # method_name = The name of the filter
  327 + # option = Filter options, like :only or :except
  328 + # block = Block that the filter will call
  329 + if method.to_s =~ /^(.+)_controller_filters$/
  330 + []
  331 + # -> Removes the action button from the content
  332 + # returns = boolean
  333 + elsif method.to_s =~ /^content_remove_(#{content_actions.join('|')})$/
  334 + nil
  335 + # -> Expire the action button from the content
  336 + # returns = string with reason of expiration
  337 + elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/
  338 + nil
  339 + else
  340 + super
  341 + end
  342 + end
  343 +
  344 + private
  345 +
  346 + def content_actions
  347 + %w[edit delete spread locale suggest home]
  348 + end
  349 +
336 end 350 end
plugins/tolerance_time/controllers/tolerance_time_plugin_myprofile_controller.rb 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +class ToleranceTimePluginMyprofileController < MyProfileController
  2 + def index
  3 + @tolerance = ToleranceTimePlugin::Tolerance.find_by_profile_id(profile.id) || ToleranceTimePlugin::Tolerance.create!(:profile => profile)
  4 + convert_values
  5 + if request.post?
  6 + begin
  7 + convert_params
  8 + @tolerance.update_attributes!(params[:tolerance])
  9 + convert_values
  10 + session[:notice] = _('Tolerance updated')
  11 + rescue
  12 + session[:notice] = _('Tolerance could not be updated')
  13 + end
  14 + end
  15 + end
  16 +
  17 + private
  18 +
  19 + def convert_params
  20 + params[:tolerance][:content_tolerance] = params[:tolerance][:content_tolerance].to_i * params[:content_tolerance_unit].to_i if !params[:tolerance][:content_tolerance].blank?
  21 + params[:tolerance][:comment_tolerance] = params[:tolerance][:comment_tolerance].to_i * params[:comment_tolerance_unit].to_i if !params[:tolerance][:comment_tolerance].blank?
  22 + end
  23 +
  24 + def convert_values
  25 + @content_default_unit = select_unit(@tolerance.content_tolerance)
  26 + @comment_default_unit = select_unit(@tolerance.comment_tolerance)
  27 + @tolerance.content_tolerance /= @content_default_unit if !@tolerance.content_tolerance.nil?
  28 + @tolerance.comment_tolerance /= @comment_default_unit if !@tolerance.comment_tolerance.nil?
  29 + end
  30 +
  31 + def select_unit(value)
  32 + return 1 if value.nil? || value == 0
  33 + return 3600 if value % 3600 == 0
  34 + return 60 if value % 60 == 0
  35 + return 1
  36 + end
  37 +end
plugins/tolerance_time/db/migrate/20120719090320_create_tolerance_time_plugin_tolerances.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class CreateToleranceTimePluginTolerances < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :tolerance_time_plugin_tolerances do |t|
  4 + t.references :profile
  5 + t.integer :content_tolerance
  6 + t.integer :comment_tolerance
  7 + end
  8 + end
  9 +
  10 + def self.down
  11 + drop_table :tolerance_time_plugin_tolerances
  12 + end
  13 +end
plugins/tolerance_time/db/migrate/20120719095004_create_tolerance_time_plugin_publications.rb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +class CreateToleranceTimePluginPublications < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :tolerance_time_plugin_publications do |t|
  4 + t.references :target, :polymorphic => true
  5 + t.timestamps
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + drop_table :tolerance_time_plugin_publications
  11 + end
  12 +end
plugins/tolerance_time/lib/ext/article.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +require_dependency 'article'
  2 +
  3 +class Article
  4 + after_create do |article|
  5 + ToleranceTimePlugin::Publication.create!(:target => article) if article.published
  6 + end
  7 +
  8 + before_save do |article|
  9 + if article.published_changed?
  10 + if article.published
  11 + ToleranceTimePlugin::Publication.create!(:target => article)
  12 + else
  13 + publication = ToleranceTimePlugin::Publication.find_by_target(article)
  14 + publication.destroy if publication.present?
  15 + end
  16 + end
  17 + end
  18 +
  19 + before_destroy do |article|
  20 + publication = ToleranceTimePlugin::Publication.find_by_target(article)
  21 + publication.destroy if publication.present?
  22 + end
  23 +end
plugins/tolerance_time/lib/ext/comment.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +require_dependency 'comment'
  2 +
  3 +class Comment
  4 + after_create do |comment|
  5 + ToleranceTimePlugin::Publication.create!(:target => comment)
  6 + end
  7 +
  8 + before_destroy do |comment|
  9 + publication = ToleranceTimePlugin::Publication.find_by_target(comment)
  10 + publication.destroy if publication.present?
  11 + end
  12 +end
  13 +
plugins/tolerance_time/lib/tolerance_time_plugin.rb 0 → 100644
@@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
  1 +require_dependency 'ext/article'
  2 +require_dependency 'ext/comment'
  3 +
  4 +class ToleranceTimePlugin < Noosfero::Plugin
  5 +
  6 + def self.plugin_name
  7 + "Tolerance Time"
  8 + end
  9 +
  10 + def self.plugin_description
  11 + _("Adds a tolerance time for editing content after its publication")
  12 + end
  13 +
  14 + def self.expired?(content)
  15 + return false if content.kind_of?(Comment) && !content.article.kind_of?(Article)
  16 +
  17 + expirable = content.kind_of?(Comment) || (!content.folder? && content.published?)
  18 + publication = ToleranceTimePlugin::Publication.find_by_target(content)
  19 + publication = ToleranceTimePlugin::Publication.create!(:target => content) if expirable && publication.nil?
  20 + person_article = content.kind_of?(Article) && content.profile.kind_of?(Person)
  21 +
  22 + !person_article && expirable && publication.expired?
  23 + end
  24 +
  25 + def control_panel_buttons
  26 + {:title => _('Tolerance Adjustements'), :url => {:controller => 'tolerance_time_plugin_myprofile', :profile => context.profile.identifier}, :icon => 'tolerance-time' }
  27 + end
  28 +
  29 + def stylesheet?
  30 + true
  31 + end
  32 +
  33 + def cms_controller_filters
  34 + return if !context.environment.plugin_enabled?(ToleranceTimePlugin)
  35 + block = lambda do
  36 + content = Article.find(params[:id])
  37 + if ToleranceTimePlugin.expired?(content)
  38 + session[:notice] = _('This content can\'t be edited anymore because it expired the tolerance time')
  39 + redirect_to content.url
  40 + end
  41 + end
  42 +
  43 + { :type => 'before_filter',
  44 + :method_name => 'expired_content',
  45 + :options => {:only => 'edit'},
  46 + :block => block }
  47 + end
  48 +
  49 + def content_viewer_controller_filters
  50 + return if !context.environment.plugin_enabled?(ToleranceTimePlugin)
  51 + block = lambda do
  52 + content = Comment.find(params[:id])
  53 + if ToleranceTimePlugin.expired?(content)
  54 + session[:notice] = _('This content can\'t be edited anymore because it expired the tolerance time')
  55 + redirect_to content.article.url
  56 + end
  57 + end
  58 +
  59 + { :type => 'before_filter',
  60 + :method_name => 'expired_content',
  61 + :options => {:only => 'edit_comment'},
  62 + :block => block }
  63 + end
  64 +
  65 + def content_expire_edit(content)
  66 + if ToleranceTimePlugin.expired?(content)
  67 + _('The tolerance time for editing this content is over.')
  68 + end
  69 + end
  70 +
  71 +end
plugins/tolerance_time/lib/tolerance_time_plugin/publication.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class ToleranceTimePlugin::Publication < Noosfero::Plugin::ActiveRecord
  2 + belongs_to :target, :polymorphic => true
  3 + validates_presence_of :target_id, :target_type
  4 + validates_uniqueness_of :target_id, :scope => :target_type
  5 +
  6 + class << self
  7 + def find_by_target(target)
  8 + kind = target.kind_of?(Article) ? 'Article' : 'Comment'
  9 + find_by_target_id_and_target_type(target.id, kind)
  10 + end
  11 + end
  12 +
  13 + def expired?
  14 + profile = (target.kind_of?(Article) ? target.profile : target.article.profile)
  15 + profile_tolerance = ToleranceTimePlugin::Tolerance.find_by_profile_id(profile.id)
  16 + content_tolerance = profile_tolerance ? profile_tolerance.content_tolerance : nil
  17 + comment_tolerance = profile_tolerance ? profile_tolerance.comment_tolerance : nil
  18 + if target.kind_of?(Article)
  19 + tolerance_time = content_tolerance || 1.0/0
  20 + elsif target.kind_of?(Comment)
  21 + tolerance_time = comment_tolerance || 1.0/0
  22 + else
  23 + tolerance_time = 1.0/0
  24 + end
  25 + created_at.to_i+tolerance_time < Time.now.to_i
  26 + end
  27 +end
plugins/tolerance_time/lib/tolerance_time_plugin/tolerance.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +class ToleranceTimePlugin::Tolerance < Noosfero::Plugin::ActiveRecord
  2 + belongs_to :profile
  3 + validates_presence_of :profile_id
  4 + validates_uniqueness_of :profile_id
  5 + validates_numericality_of :content_tolerance, :only_integer => true, :allow_nil => true
  6 + validates_numericality_of :comment_tolerance, :only_integer => true, :allow_nil => true
  7 +end
plugins/tolerance_time/public/icons/tolerance-time.png 0 → 100644

4.71 KB

plugins/tolerance_time/public/style.css 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +.controller-profile_editor a.control-panel-tolerance-time,
  2 +.controller-profile_editor .msie6 a.control-panel-tolerance-time {
  3 + background-image: url(/plugins/tolerance_time/icons/tolerance-time.png)
  4 +}
plugins/tolerance_time/test/unit/article_test.rb 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class ArticleTest < ActiveSupport::TestCase
  4 + should 'create a publication after publishing the article' do
  5 + article = fast_create(Article, :published => false, :profile_id => fast_create(Profile).id)
  6 + assert_nil ToleranceTimePlugin::Publication.find_by_target(article)
  7 +
  8 + article.published = true
  9 + article.save!
  10 + assert_not_nil ToleranceTimePlugin::Publication.find_by_target(article)
  11 + end
  12 +
  13 + should 'destroy publication if the article is destroyed' do
  14 + profile = fast_create(Profile)
  15 + article = fast_create(Article, :profile_id => profile.id)
  16 + article_publication = ToleranceTimePlugin::Publication.create!(:target => article)
  17 + article.destroy
  18 + assert_raise ActiveRecord::RecordNotFound do
  19 + article_publication.reload
  20 + end
  21 + end
  22 +
  23 + should 'destroy publication if the article is changed to not published' do
  24 + profile = fast_create(Profile)
  25 + article = fast_create(Article, :profile_id => profile.id)
  26 + article_publication = ToleranceTimePlugin::Publication.create!(:target => article)
  27 + article.published = false
  28 + article.save!
  29 + assert_raise ActiveRecord::RecordNotFound do
  30 + article_publication.reload
  31 + end
  32 + end
  33 +end
plugins/tolerance_time/test/unit/comment_test.rb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class CommentTest < ActiveSupport::TestCase
  4 + should 'create a publication after posting a comment' do
  5 + article = fast_create(Article, :profile_id => fast_create(Person).id)
  6 + comment = Comment.new(:author_id => fast_create(Person).id, :body => 'Hello There!', :source_id => article.id)
  7 + assert_difference ToleranceTimePlugin::Publication, :count do
  8 + comment.save!
  9 + end
  10 + assert_not_nil ToleranceTimePlugin::Publication.find_by_target(comment)
  11 + end
  12 +
  13 + should 'destroy publication if the comment is destroyed' do
  14 + profile = fast_create(Profile)
  15 + article = fast_create(Article, :profile_id => profile.id)
  16 + comment = fast_create(Comment, :source_id => article.id)
  17 + comment_publication = ToleranceTimePlugin::Publication.create!(:target => comment)
  18 + comment.destroy
  19 + assert_raise ActiveRecord::RecordNotFound do
  20 + comment_publication.reload
  21 + end
  22 + end
  23 +end
  24 +
plugins/tolerance_time/test/unit/tolerance_time_plugin/publication_test.rb 0 → 100644
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class ToleranceTimePlugin::PublicationTest < ActiveSupport::TestCase
  4 + should 'validate presence of target' do
  5 + publication = ToleranceTimePlugin::Publication.new
  6 + publication.valid?
  7 + assert publication.errors.invalid?(:target_id)
  8 + assert publication.errors.invalid?(:target_type)
  9 +
  10 + publication.target = fast_create(Article)
  11 + publication.valid?
  12 + assert !publication.errors.invalid?(:target_id)
  13 + assert !publication.errors.invalid?(:target_type)
  14 + end
  15 +
  16 + should 'validate uniqueness of target' do
  17 + target = fast_create(Article)
  18 + p1 = ToleranceTimePlugin::Publication.create!(:target => target)
  19 + p2 = ToleranceTimePlugin::Publication.new(:target => target)
  20 + p2.valid?
  21 +
  22 + assert p2.errors.invalid?(:target_id)
  23 + end
  24 +
  25 + should 'be able to find publication by target' do
  26 + article = fast_create(Article)
  27 + publication = ToleranceTimePlugin::Publication.create!(:target => article)
  28 + assert_equal publication, ToleranceTimePlugin::Publication.find_by_target(article)
  29 + end
  30 +
  31 + should 'avaliate if the publication is expired' do
  32 + profile = fast_create(Profile)
  33 + author = fast_create(Person)
  34 + a1 = fast_create(Article, :profile_id => profile.id)
  35 + a2 = fast_create(Article, :profile_id => profile.id)
  36 + c1 = fast_create(Comment, :source_id => a1.id)
  37 + c2 = fast_create(Comment, :source_id => a2.id)
  38 + ToleranceTimePlugin::Tolerance.create!(:profile => profile, :content_tolerance => 10.minutes, :comment_tolerance => 5.minutes)
  39 + expired_article = ToleranceTimePlugin::Publication.create!(:target => a1)
  40 + expired_article.created_at = 15.minutes.ago
  41 + expired_article.save!
  42 + on_time_article = ToleranceTimePlugin::Publication.create!(:target => a2)
  43 + on_time_article.created_at = 5.minutes.ago
  44 + on_time_article.save!
  45 + expired_comment = ToleranceTimePlugin::Publication.create!(:target => c1)
  46 + expired_comment.created_at = 8.minutes.ago
  47 + expired_comment.save!
  48 + on_time_comment = ToleranceTimePlugin::Publication.create!(:target => c2)
  49 + on_time_comment.created_at = 2.minutes.ago
  50 + on_time_comment.save!
  51 +
  52 + assert expired_article.expired?
  53 + assert !on_time_article.expired?
  54 + assert expired_comment.expired?
  55 + assert !on_time_comment.expired?
  56 + end
  57 +
  58 + should 'consider tolerance infinity if not defined' do
  59 + profile = fast_create(Profile)
  60 + article = fast_create(Article, :profile_id => profile.id)
  61 + article_publication = ToleranceTimePlugin::Publication.create!(:target => article)
  62 + article_publication.created_at = 1000.years.ago
  63 + article_publication.save!
  64 + ToleranceTimePlugin::Tolerance.create!(:profile => profile)
  65 +
  66 + assert !article_publication.expired?
  67 + end
  68 +
  69 + should 'not crash if profile has no tolerance yet defined' do
  70 + profile = fast_create(Profile)
  71 + article = fast_create(Article, :profile_id => profile.id)
  72 + article_publication = ToleranceTimePlugin::Publication.create!(:target => article)
  73 + article_publication.created_at = 1000.years.ago
  74 + article_publication.save!
  75 +
  76 + assert !article_publication.expired?
  77 + end
  78 +end
plugins/tolerance_time/test/unit/tolerance_time_plugin/tolerance_test.rb 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +require File.dirname(__FILE__) + '/../../../../../test/test_helper'
  2 +
  3 +class ToleranceTimePlugin::ToleranceTest < ActiveSupport::TestCase
  4 + should 'validate presence of profile' do
  5 + tolerance = ToleranceTimePlugin::Tolerance.new
  6 + tolerance.valid?
  7 + assert tolerance.errors.invalid?(:profile_id)
  8 +
  9 + tolerance.profile = fast_create(Profile)
  10 + tolerance.valid?
  11 + assert !tolerance.errors.invalid?(:profile_id)
  12 + end
  13 +
  14 + should 'validate uniqueness of profile' do
  15 + profile = fast_create(Profile)
  16 + t1 = ToleranceTimePlugin::Tolerance.create!(:profile => profile)
  17 + t2 = ToleranceTimePlugin::Tolerance.new(:profile => profile)
  18 + t2.valid?
  19 +
  20 + assert t2.errors.invalid?(:profile_id)
  21 + end
  22 +
  23 + should 'validate integer format for comment and content tolerance' do
  24 + tolerance = ToleranceTimePlugin::Tolerance.new(:profile => fast_create(Profile))
  25 + assert tolerance.valid?
  26 +
  27 + tolerance.comment_tolerance = 'sdfa'
  28 + tolerance.content_tolerance = 4.5
  29 + tolerance.valid?
  30 + assert tolerance.errors.invalid?(:comment_tolerance)
  31 + assert tolerance.errors.invalid?(:content_tolerance)
  32 +
  33 + tolerance.comment_tolerance = 3
  34 + tolerance.content_tolerance = 6
  35 + assert tolerance.valid?
  36 + end
  37 +end
plugins/tolerance_time/views/tolerance_time_plugin_myprofile/index.html.erb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +<h1><%= _('Tolerance Adjustments') %></h1>
  2 +
  3 +<%= error_messages_for :tolerance %>
  4 +
  5 +<% form_for :tolerance, @tolerance do |f| %>
  6 +
  7 + <% time_units = [[_('Seconds'), 1], [_('Minutes'), 60], [_('Hours'), 3600]]%>
  8 +
  9 + <% if profile.organization? %>
  10 + <%= labelled_form_field(_('Content edition tolerance time'),
  11 + f.text_field(:content_tolerance, :size => 2, :style => 'font-size: 14px; text-align: right') +
  12 + select_tag(:content_tolerance_unit, options_for_select(time_units, @content_default_unit) )) %>
  13 + <% end %>
  14 + <%= labelled_form_field(_('Comment edition tolerance time'),
  15 + f.text_field(:comment_tolerance, :size => 2, :style => 'font-size: 14px; text-align: right') +
  16 + select_tag(:comment_tolerance_unit, options_for_select(time_units, @comment_default_unit) )) %>
  17 +
  18 + <%= content_tag( 'small', _('Empty means unlimited and zero means right away.') ) %>
  19 +
  20 + <% button_bar do %>
  21 + <%= submit_button('save', _('Save'))%>
  22 + <%= button('back', _('Back'), {:controller => 'profile_editor'})%>
  23 + <% end %>
  24 +<% end %>
public/designs/icons/tango/ie6.css
1 .msie6 .icon-edit { background-image: url(ie6/Tango/16x16/apps/text-editor.gif) } 1 .msie6 .icon-edit { background-image: url(ie6/Tango/16x16/apps/text-editor.gif) }
2 .msie6 .icon-home { background-image: url(ie6/Tango/16x16/actions/go-home.gif) } 2 .msie6 .icon-home { background-image: url(ie6/Tango/16x16/actions/go-home.gif) }
3 -.msie6 .icon-new { background-image: url(ie6/Tango/16x16/actions/filenew.gif) } 3 +.msie6 .icon-new,
  4 +.msie6 .icon-suggest { background-image: url(ie6/Tango/16x16/actions/filenew.gif) }
4 .msie6 .icon-close { background-image: url(ie6/Tango/16x16/actions/gtk-cancel.gif) } 5 .msie6 .icon-close { background-image: url(ie6/Tango/16x16/actions/gtk-cancel.gif) }
5 .msie6 .icon-newfolder { background-image: url(ie6/Tango/16x16/actions/folder-new.gif) } 6 .msie6 .icon-newfolder { background-image: url(ie6/Tango/16x16/actions/folder-new.gif) }
6 .msie6 .icon-save { background-image: url(ie6/Tango/16x16/actions/filesave.gif) } 7 .msie6 .icon-save { background-image: url(ie6/Tango/16x16/actions/filesave.gif) }
public/designs/icons/tango/style.css
@@ -3,7 +3,8 @@ @@ -3,7 +3,8 @@
3 /******************SMALL ICONS********************/ 3 /******************SMALL ICONS********************/
4 .icon-edit { background-image: url(Tango/16x16/apps/text-editor.png) } 4 .icon-edit { background-image: url(Tango/16x16/apps/text-editor.png) }
5 .icon-home { background-image: url(Tango/16x16/actions/go-home.png) } 5 .icon-home { background-image: url(Tango/16x16/actions/go-home.png) }
6 -.icon-new { background-image: url(Tango/16x16/actions/filenew.png) } 6 +.icon-new,
  7 +.icon-suggest { background-image: url(Tango/16x16/actions/filenew.png) }
7 .icon-close { background-image: url(Tango/16x16/actions/gtk-cancel.png) } 8 .icon-close { background-image: url(Tango/16x16/actions/gtk-cancel.png) }
8 .icon-newfolder { background-image: url(Tango/16x16/actions/folder-new.png) } 9 .icon-newfolder { background-image: url(Tango/16x16/actions/folder-new.png) }
9 .icon-folder { background-image: url(Tango/16x16/places/folder.png) } 10 .icon-folder { background-image: url(Tango/16x16/places/folder.png) }
public/designs/themes/base/style.css
@@ -908,6 +908,16 @@ hr.pre-posts, hr.sep-posts { @@ -908,6 +908,16 @@ hr.pre-posts, hr.sep-posts {
908 #article-actions a.button:hover { 908 #article-actions a.button:hover {
909 color: #555753; 909 color: #555753;
910 } 910 }
  911 +#content a.disabled,
  912 +#content a.disabled:hover {
  913 + color: #888;
  914 + text-decoration: none;
  915 +}
  916 +#content a.button.disabled,
  917 +#content a.button.disabled:hover {
  918 + background-color: #CCC;
  919 + border-color: #CCC;
  920 +}
911 921
912 #addThis { 922 #addThis {
913 text-align: right; 923 text-align: right;
public/filters.svg 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<svg xmlns="http://www.w3.org/2000/svg">
  2 + <filter id="grayscale">
  3 + <feColorMatrix type="matrix" values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"/>
  4 + </filter>
  5 +</svg>
public/stylesheets/application.css
@@ -1503,7 +1503,13 @@ a.button:hover, body.noosfero a.button:hover, input.button:hover, a.button.with- @@ -1503,7 +1503,13 @@ a.button:hover, body.noosfero a.button:hover, input.button:hover, a.button.with-
1503 body.noosfero a.button.with-text.icon-none, body.noosfero input.button.with-text.icon-none { 1503 body.noosfero a.button.with-text.icon-none, body.noosfero input.button.with-text.icon-none {
1504 padding-left: 2px; 1504 padding-left: 2px;
1505 } 1505 }
1506 -a.button.disabled, input.disabled { 1506 +a.disabled{
  1507 + filter: url(filters.svg#grayscale); /* Firefox 3.5+ */
  1508 + filter: gray; /* IE6-9 */
  1509 + -webkit-filter: grayscale(1); /* Google Chrome & Safari 6+ */
  1510 + cursor: default;
  1511 +}
  1512 +input.disabled {
1507 opacity: 0.5; 1513 opacity: 0.5;
1508 filter-opacity: 50%; 1514 filter-opacity: 50%;
1509 } 1515 }
test/factories.rb
@@ -442,7 +442,7 @@ module Noosfero::Factory @@ -442,7 +442,7 @@ module Noosfero::Factory
442 442
443 def defaults_for_comment(params = {}) 443 def defaults_for_comment(params = {})
444 name = "comment_#{rand(1000)}" 444 name = "comment_#{rand(1000)}"
445 - { :title => name, :body => "my own comment", :source_id => 1 }.merge(params) 445 + { :title => name, :body => "my own comment", :source_id => 1, :source_type => 'Article' }.merge(params)
446 end 446 end
447 447
448 ############################################### 448 ###############################################
test/functional/content_viewer_controller_test.rb
@@ -1400,6 +1400,38 @@ end @@ -1400,6 +1400,38 @@ end
1400 end 1400 end
1401 end 1401 end
1402 1402
  1403 + should 'not display article actions button if any plugins says so' do
  1404 + class Plugin1 < Noosfero::Plugin
  1405 + def content_remove_edit(content); true; end
  1406 + end
  1407 + class Plugin2 < Noosfero::Plugin
  1408 + def content_remove_edit(content); false; end
  1409 + end
  1410 +
  1411 + environment.enable_plugin(Plugin1.name)
  1412 + environment.enable_plugin(Plugin2.name)
  1413 +
  1414 + login_as('testinguser')
  1415 + xhr :get, :view_page, :profile => 'testinguser', :page => [], :toolbar => true
  1416 + assert_no_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :href => "/myprofile/testinguser/cms/edit/#{profile.home_page.id}" } }
  1417 + end
  1418 +
  1419 + should 'expire article actions button if any plugins says so' do
  1420 + class Plugin1 < Noosfero::Plugin
  1421 + def content_expire_edit(content); 'This button is expired.'; end
  1422 + end
  1423 + class Plugin2 < Noosfero::Plugin
  1424 + def content_expire_edit(content); nil; end
  1425 + end
  1426 +
  1427 + environment.enable_plugin(Plugin1.name)
  1428 + environment.enable_plugin(Plugin2.name)
  1429 +
  1430 + login_as('testinguser')
  1431 + xhr :get, :view_page, :profile => 'testinguser', :page => [], :toolbar => true
  1432 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => 'This button is expired.', :class => 'button with-text icon-edit disabled' } }
  1433 + end
  1434 +
1403 should 'remove email from article followers when unfollow' do 1435 should 'remove email from article followers when unfollow' do
1404 profile = create_user('testuser').person 1436 profile = create_user('testuser').person
1405 follower_email = 'john@doe.br' 1437 follower_email = 'john@doe.br'
test/unit/cms_helper_test.rb
@@ -5,6 +5,7 @@ class CmsHelperTest &lt; ActiveSupport::TestCase @@ -5,6 +5,7 @@ class CmsHelperTest &lt; ActiveSupport::TestCase
5 include CmsHelper 5 include CmsHelper
6 include BlogHelper 6 include BlogHelper
7 include ApplicationHelper 7 include ApplicationHelper
  8 + include ActionView::Helpers::UrlHelper
8 9
9 should 'show default options for article' do 10 should 'show default options for article' do
10 CmsHelperTest.any_instance.stubs(:controller).returns(ActionController::Base.new) 11 CmsHelperTest.any_instance.stubs(:controller).returns(ActionController::Base.new)
@@ -47,14 +48,18 @@ class CmsHelperTest &lt; ActiveSupport::TestCase @@ -47,14 +48,18 @@ class CmsHelperTest &lt; ActiveSupport::TestCase
47 end 48 end
48 49
49 should 'display spread button when profile is a person' do 50 should 'display spread button when profile is a person' do
  51 + @controller = ApplicationController.new
  52 + @plugins.stubs(:dispatch).returns([])
50 profile = fast_create(Person) 53 profile = fast_create(Person)
51 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id) 54 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id)
52 - expects(:button_without_text).with(:spread, 'Spread this', :action => 'publish', :id => article.id) 55 + expects(:link_to).with('Spread this', {:action => 'publish', :id => article.id}, :class => 'button with-text icon-spread', :title => nil)
53 56
54 result = display_spread_button(profile, article) 57 result = display_spread_button(profile, article)
55 end 58 end
56 59
57 should 'display spread button when profile is a community and env has portal_community' do 60 should 'display spread button when profile is a community and env has portal_community' do
  61 + @controller = ApplicationController.new
  62 + @plugins.stubs(:dispatch).returns([])
58 env = fast_create(Environment) 63 env = fast_create(Environment)
59 env.expects(:portal_community).returns(true) 64 env.expects(:portal_community).returns(true)
60 profile = fast_create(Community, :environment_id => env.id) 65 profile = fast_create(Community, :environment_id => env.id)
@@ -62,12 +67,14 @@ class CmsHelperTest &lt; ActiveSupport::TestCase @@ -62,12 +67,14 @@ class CmsHelperTest &lt; ActiveSupport::TestCase
62 67
63 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id) 68 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id)
64 69
65 - expects(:button_without_text).with(:spread, 'Spread this', :action => 'publish_on_portal_community', :id => article.id) 70 + expects(:link_to).with('Spread this', {:action => 'publish_on_portal_community', :id => article.id}, :class => 'button with-text icon-spread', :title => nil)
66 71
67 result = display_spread_button(profile, article) 72 result = display_spread_button(profile, article)
68 end 73 end
69 74
70 should 'not display spread button when profile is a community and env has not portal_community' do 75 should 'not display spread button when profile is a community and env has not portal_community' do
  76 + @controller = ApplicationController.new
  77 + @plugins.stubs(:dispatch).returns([])
71 env = fast_create(Environment) 78 env = fast_create(Environment)
72 env.expects(:portal_community).returns(nil) 79 env.expects(:portal_community).returns(nil)
73 profile = fast_create(Community, :environment_id => env.id) 80 profile = fast_create(Community, :environment_id => env.id)
@@ -75,31 +82,37 @@ class CmsHelperTest &lt; ActiveSupport::TestCase @@ -75,31 +82,37 @@ class CmsHelperTest &lt; ActiveSupport::TestCase
75 82
76 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id) 83 article = fast_create(TinyMceArticle, :name => 'My article', :profile_id => profile.id)
77 84
78 - expects(:button_without_text).with(:spread, 'Spread this', :action => 'publish_on_portal_community', :id => article.id).never 85 + expects(:link_to).with('Spread this', {:action => 'publish_on_portal_community', :id => article.id}, :class => 'button with-text icon-spread', :title => nil).never
79 86
80 result = display_spread_button(profile, article) 87 result = display_spread_button(profile, article)
81 end 88 end
82 89
83 should 'display delete_button to folder' do 90 should 'display delete_button to folder' do
  91 + @controller = ApplicationController.new
  92 + @plugins.stubs(:dispatch).returns([])
84 profile = fast_create(Profile) 93 profile = fast_create(Profile)
85 name = 'My folder' 94 name = 'My folder'
86 folder = fast_create(Folder, :name => name, :profile_id => profile.id) 95 folder = fast_create(Folder, :name => name, :profile_id => profile.id)
87 confirm_message = "Are you sure that you want to remove the folder \"#{name}\"? Note that all the items inside it will also be removed!" 96 confirm_message = "Are you sure that you want to remove the folder \"#{name}\"? Note that all the items inside it will also be removed!"
88 - expects(:button_without_text).with(:delete, 'Delete', {:action => 'destroy', :id => folder.id}, :method => :post, :confirm => confirm_message) 97 + expects(:link_to).with('Delete', {:action => 'destroy', :id => folder.id}, :method => :post, :confirm => confirm_message, :class => 'button with-text icon-delete', :title => nil)
89 98
90 result = display_delete_button(folder) 99 result = display_delete_button(folder)
91 end 100 end
92 101
93 should 'display delete_button to article' do 102 should 'display delete_button to article' do
  103 + @controller = ApplicationController.new
  104 + @plugins.stubs(:dispatch).returns([])
94 profile = fast_create(Profile) 105 profile = fast_create(Profile)
95 name = 'My article' 106 name = 'My article'
96 article = fast_create(TinyMceArticle, :name => name, :profile_id => profile.id) 107 article = fast_create(TinyMceArticle, :name => name, :profile_id => profile.id)
97 confirm_message = "Are you sure that you want to remove the item \"#{name}\"?" 108 confirm_message = "Are you sure that you want to remove the item \"#{name}\"?"
98 - expects(:button_without_text).with(:delete, 'Delete', {:action => 'destroy', :id => article.id}, :method => :post, :confirm => confirm_message) 109 + expects(:link_to).with('Delete', {:action => 'destroy', :id => article.id}, :method => :post, :confirm => confirm_message, :class => 'button with-text icon-delete', :title => nil)
99 110
100 result = display_delete_button(article) 111 result = display_delete_button(article)
101 end 112 end
102 113
  114 + def link_to(text, *args); puts text; puts args.inspect; text; end
  115 +
103 end 116 end
104 117
105 module RssFeedHelper 118 module RssFeedHelper
test/unit/comment_test.rb
@@ -555,6 +555,14 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -555,6 +555,14 @@ class CommentTest &lt; ActiveSupport::TestCase
555 assert_equal 'bar', c.referrer 555 assert_equal 'bar', c.referrer
556 end 556 end
557 557
  558 + should 'delegate environment to article' do
  559 + profile = fast_create(Profile, :environment_id => Environment.default)
  560 + article = fast_create(Article, :profile_id => profile.id)
  561 + comment = fast_create(Comment, :source_id => article.id, :source_type => 'Article')
  562 +
  563 + assert_equal Environment.default, comment.environment
  564 + end
  565 +
558 private 566 private
559 567
560 def create_comment(args = {}) 568 def create_comment(args = {})