Commit fc8557c3c6c62a489bab035ea63f3ee7a10c5db0
Exists in
staging
and in
42 other branches
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 | + | ||
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/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 |
@@ -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 |
@@ -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 | + |
@@ -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 |
4.71 KB
@@ -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 |
@@ -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/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 < ActiveSupport::TestCase | @@ -5,6 +5,7 @@ class CmsHelperTest < 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 < ActiveSupport::TestCase | @@ -47,14 +48,18 @@ class CmsHelperTest < 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 < ActiveSupport::TestCase | @@ -62,12 +67,14 @@ class CmsHelperTest < 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 < ActiveSupport::TestCase | @@ -75,31 +82,37 @@ class CmsHelperTest < 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 < ActiveSupport::TestCase | @@ -555,6 +555,14 @@ class CommentTest < 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 = {}) |