Commit 4f91184d39168c2105c77c1ad61fe0c5f2337789
Exists in
master
and in
29 other branches
Merge branch 'merge-requests/282'
Showing
37 changed files
with
1993 additions
and
681 deletions
Show diff stats
... | ... | @@ -0,0 +1,164 @@ |
1 | +class CommentController < ApplicationController | |
2 | + | |
3 | + needs_profile | |
4 | + | |
5 | + before_filter :can_update?, :only => [:edit, :update] | |
6 | + | |
7 | + def create | |
8 | + begin | |
9 | + @page = profile.articles.find(params[:id]) | |
10 | + rescue | |
11 | + @page = nil | |
12 | + end | |
13 | + | |
14 | + # page not found, give error | |
15 | + if @page.nil? | |
16 | + respond_to do |format| | |
17 | + format.js do | |
18 | + render :json => { :msg => _('Page not found.')} | |
19 | + end | |
20 | + end | |
21 | + return | |
22 | + end | |
23 | + | |
24 | + unless @page.accept_comments? | |
25 | + respond_to do |format| | |
26 | + format.js do | |
27 | + render :json => { :msg => _('Comment not allowed in this article')} | |
28 | + end | |
29 | + end | |
30 | + return | |
31 | + end | |
32 | + | |
33 | + @comment = Comment.new(params[:comment]) | |
34 | + @comment.author = user if logged_in? | |
35 | + @comment.article = @page | |
36 | + @comment.ip_address = request.remote_ip | |
37 | + @comment.user_agent = request.user_agent | |
38 | + @comment.referrer = request.referrer | |
39 | + @plugins.dispatch(:filter_comment, @comment) | |
40 | + | |
41 | + if @comment.rejected? | |
42 | + respond_to do |format| | |
43 | + format.js do | |
44 | + render :json => { :msg => _('Comment was rejected')} | |
45 | + end | |
46 | + end | |
47 | + return | |
48 | + end | |
49 | + | |
50 | + if !@comment.valid? || (not pass_without_comment_captcha? and not verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) | |
51 | + respond_to do |format| | |
52 | + format.js do | |
53 | + render :json => { | |
54 | + :render_target => 'form', | |
55 | + :html => render_to_string(:partial => 'comment_form', :object => @comment, :locals => {:comment => @comment, :display_link => true, :show_form => true}) | |
56 | + } | |
57 | + end | |
58 | + end | |
59 | + return | |
60 | + end | |
61 | + | |
62 | + if @comment.need_moderation? | |
63 | + @comment.created_at = Time.now | |
64 | + ApproveComment.create!(:requestor => @comment.author, :target => profile, :comment_attributes => @comment.attributes.to_json) | |
65 | + | |
66 | + respond_to do |format| | |
67 | + format.js do | |
68 | + render :json => { :render_target => nil, :msg => _('Your comment is waiting for approval.') } | |
69 | + end | |
70 | + end | |
71 | + return | |
72 | + end | |
73 | + | |
74 | + @comment.save | |
75 | + | |
76 | + respond_to do |format| | |
77 | + format.js do | |
78 | + comment_to_render = @comment.comment_root | |
79 | + render :json => { | |
80 | + :render_target => comment_to_render.anchor, | |
81 | + :html => render_to_string(:partial => 'comment', :locals => {:comment => comment_to_render, :display_link => true}), | |
82 | + :msg => _('Comment successfully created.') | |
83 | + } | |
84 | + end | |
85 | + end | |
86 | + end | |
87 | + | |
88 | + def destroy | |
89 | + comment = profile.comments_received.find(params[:id]) | |
90 | + | |
91 | + if comment && comment.can_be_destroyed_by?(user) && comment.destroy | |
92 | + render :text => {'ok' => true}.to_json, :content_type => 'application/json' | |
93 | + else | |
94 | + session[:notice] = _("The comment was not removed.") | |
95 | + render :text => {'ok' => false}.to_json, :content_type => 'application/json' | |
96 | + end | |
97 | + end | |
98 | + | |
99 | + def mark_as_spam | |
100 | + comment = profile.comments_received.find(params[:id]) | |
101 | + if comment.can_be_marked_as_spam_by?(user) | |
102 | + comment.spam! | |
103 | + render :text => {'ok' => true}.to_json, :content_type => 'application/json' | |
104 | + else | |
105 | + session[:notice] = _("You couldn't mark this comment as spam.") | |
106 | + render :text => {'ok' => false}.to_json, :content_type => 'application/json' | |
107 | + end | |
108 | + end | |
109 | + | |
110 | + def edit | |
111 | + render :partial => "comment_form", :locals => {:comment => @comment, :display_link => params[:reply_of_id].present?, :edition_mode => true, :show_form => true} | |
112 | + end | |
113 | + | |
114 | + def update | |
115 | + if @comment.update_attributes(params[:comment]) | |
116 | + respond_to do |format| | |
117 | + format.js do | |
118 | + comment_to_render = @comment.comment_root | |
119 | + render :json => { | |
120 | + :ok => true, | |
121 | + :render_target => comment_to_render.anchor, | |
122 | + :html => render_to_string(:partial => 'comment', :locals => {:comment => comment_to_render}) | |
123 | + } | |
124 | + end | |
125 | + end | |
126 | + else | |
127 | + respond_to do |format| | |
128 | + format.js do | |
129 | + render :json => { | |
130 | + :ok => false, | |
131 | + :render_target => 'form', | |
132 | + :html => render_to_string(:partial => 'comment_form', :object => @comment, :locals => {:comment => @comment, :display_link => false, :edition_mode => true, :show_form => true}) | |
133 | + } | |
134 | + end | |
135 | + end | |
136 | + end | |
137 | + end | |
138 | + | |
139 | + def check_actions | |
140 | + comment = profile.comments_received.find(params[:id]) | |
141 | + ids = @plugins.dispatch(:check_comment_actions, comment).collect do |action| | |
142 | + action.kind_of?(Proc) ? self.instance_eval(&action) : action | |
143 | + end.flatten.compact | |
144 | + render :json => {:ids => ids} | |
145 | + end | |
146 | + | |
147 | + protected | |
148 | + | |
149 | + def pass_without_comment_captcha? | |
150 | + logged_in? && !environment.enabled?('captcha_for_logged_users') | |
151 | + end | |
152 | + helper_method :pass_without_comment_captcha? | |
153 | + | |
154 | + def can_update? | |
155 | + begin | |
156 | + @comment = profile.comments_received.find(params[:id]) | |
157 | + raise ActiveRecord::RecordNotFound unless @comment.can_be_updated_by?(user) # Not reveal that the comment exists | |
158 | + rescue ActiveRecord::RecordNotFound | |
159 | + render_not_found | |
160 | + return | |
161 | + end | |
162 | + end | |
163 | + | |
164 | +end | ... | ... |
app/controllers/public/content_viewer_controller.rb
... | ... | @@ -2,8 +2,6 @@ class ContentViewerController < ApplicationController |
2 | 2 | |
3 | 3 | needs_profile |
4 | 4 | |
5 | - before_filter :comment_author, :only => :edit_comment | |
6 | - | |
7 | 5 | helper ProfileHelper |
8 | 6 | helper TagsHelper |
9 | 7 | |
... | ... | @@ -70,24 +68,8 @@ class ContentViewerController < ApplicationController |
70 | 68 | |
71 | 69 | @form_div = params[:form] |
72 | 70 | |
73 | - if params[:comment] && params[:confirm] == 'true' | |
74 | - @comment = Comment.new(params[:comment]) | |
75 | - if request.post? && @page.accept_comments? | |
76 | - add_comment | |
77 | - end | |
78 | - else | |
79 | - @comment = Comment.new | |
80 | - end | |
81 | - | |
82 | - if request.post? | |
83 | - if params[:remove_comment] | |
84 | - remove_comment | |
85 | - return | |
86 | - elsif params[:mark_comment_as_spam] | |
87 | - mark_comment_as_spam | |
88 | - return | |
89 | - end | |
90 | - end | |
71 | + #FIXME see a better way to do this. It's not need to pass this variable anymore | |
72 | + @comment = Comment.new | |
91 | 73 | |
92 | 74 | if @page.has_posts? |
93 | 75 | posts = if params[:year] and params[:month] |
... | ... | @@ -125,81 +107,8 @@ class ContentViewerController < ApplicationController |
125 | 107 | end |
126 | 108 | end |
127 | 109 | |
128 | - def edit_comment | |
129 | - path = params[:page].join('/') | |
130 | - @page = profile.articles.find_by_path(path) | |
131 | - @form_div = 'opened' | |
132 | - @comment = @page.comments.find_by_id(params[:id]) | |
133 | - if @comment | |
134 | - if request.post? | |
135 | - begin | |
136 | - @comment.update_attributes(params[:comment]) | |
137 | - session[:notice] = _('Comment succesfully updated') | |
138 | - redirect_to :action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path | |
139 | - rescue | |
140 | - session[:notice] = _('Comment could not be updated') | |
141 | - end | |
142 | - end | |
143 | - else | |
144 | - redirect_to @page.view_url | |
145 | - session[:notice] = _('Could not find the comment in the article') | |
146 | - end | |
147 | - end | |
148 | - | |
149 | 110 | protected |
150 | 111 | |
151 | - def add_comment | |
152 | - @comment.author = user if logged_in? | |
153 | - @comment.article = @page | |
154 | - @comment.ip_address = request.remote_ip | |
155 | - @comment.user_agent = request.user_agent | |
156 | - @comment.referrer = request.referrer | |
157 | - plugins_filter_comment(@comment) | |
158 | - return if @comment.rejected? | |
159 | - if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save | |
160 | - @page.touch | |
161 | - @comment = nil # clear the comment form | |
162 | - redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | |
163 | - else | |
164 | - @form_div = 'opened' if params[:comment][:reply_of_id].blank? | |
165 | - end | |
166 | - end | |
167 | - | |
168 | - def plugins_filter_comment(comment) | |
169 | - @plugins.each do |plugin| | |
170 | - plugin.filter_comment(comment) | |
171 | - end | |
172 | - end | |
173 | - | |
174 | - def pass_without_comment_captcha? | |
175 | - logged_in? && !environment.enabled?('captcha_for_logged_users') | |
176 | - end | |
177 | - helper_method :pass_without_comment_captcha? | |
178 | - | |
179 | - def remove_comment | |
180 | - @comment = @page.comments.find(params[:remove_comment]) | |
181 | - if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) | |
182 | - @comment.destroy | |
183 | - end | |
184 | - finish_comment_handling | |
185 | - end | |
186 | - | |
187 | - def mark_comment_as_spam | |
188 | - @comment = @page.comments.find(params[:mark_comment_as_spam]) | |
189 | - if logged_in? && (user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) | |
190 | - @comment.spam! | |
191 | - end | |
192 | - finish_comment_handling | |
193 | - end | |
194 | - | |
195 | - def finish_comment_handling | |
196 | - if request.xhr? | |
197 | - render :text => {'ok' => true}.to_json, :content_type => 'application/json' | |
198 | - else | |
199 | - redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | |
200 | - end | |
201 | - end | |
202 | - | |
203 | 112 | def per_page |
204 | 113 | 12 |
205 | 114 | end |
... | ... | @@ -223,13 +132,9 @@ class ContentViewerController < ApplicationController |
223 | 132 | end |
224 | 133 | end |
225 | 134 | |
226 | - def comment_author | |
227 | - comment = Comment.find_by_id(params[:id]) | |
228 | - if comment | |
229 | - render_access_denied if comment.author.blank? || comment.author != user | |
230 | - else | |
231 | - render_not_found | |
232 | - end | |
135 | + def pass_without_comment_captcha? | |
136 | + logged_in? && !environment.enabled?('captcha_for_logged_users') | |
233 | 137 | end |
138 | + helper_method :pass_without_comment_captcha? | |
234 | 139 | |
235 | 140 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -30,6 +30,8 @@ module ApplicationHelper |
30 | 30 | |
31 | 31 | include AccountHelper |
32 | 32 | |
33 | + include CommentHelper | |
34 | + | |
33 | 35 | include BlogHelper |
34 | 36 | |
35 | 37 | include ContentViewerHelper |
... | ... | @@ -1385,12 +1387,12 @@ module ApplicationHelper |
1385 | 1387 | end |
1386 | 1388 | |
1387 | 1389 | def expirable_button(content, action, text, url, options = {}) |
1388 | - options[:class] = "button with-text icon-#{action.to_s}" | |
1390 | + options[:class] = ["button with-text icon-#{action.to_s}", options[:class]].compact.join(' ') | |
1389 | 1391 | expirable_content_reference content, action, text, url, options |
1390 | 1392 | end |
1391 | 1393 | |
1392 | 1394 | def expirable_comment_link(content, action, text, url, options = {}) |
1393 | - options[:class] = "comment-footer comment-footer-link comment-footer-hide" | |
1395 | + options[:class] = ["comment-footer comment-footer-link comment-footer-hide", options[:class]].compact.join(' ') | |
1394 | 1396 | expirable_content_reference content, action, text, url, options |
1395 | 1397 | end |
1396 | 1398 | ... | ... |
app/helpers/article_helper.rb
... | ... | @@ -35,7 +35,13 @@ module ArticleHelper |
35 | 35 | 'div', |
36 | 36 | check_box(:article, :notify_comments) + |
37 | 37 | content_tag('label', _('I want to receive a notification of each comment written by e-mail'), :for => 'article_notify_comments') + |
38 | - observe_field(:article_accept_comments, :function => "$('article_notify_comments').disabled = ! $('article_accept_comments').checked") | |
38 | + observe_field(:article_accept_comments, :function => "$('article_notify_comments').disabled = ! $('article_accept_comments').checked;$('article_moderate_comments').disabled = ! $('article_accept_comments').checked") | |
39 | + ) + | |
40 | + | |
41 | + content_tag( | |
42 | + 'div', | |
43 | + check_box(:article, :moderate_comments) + | |
44 | + content_tag('label', _('I want to approve comments on this article'), :for => 'article_moderate_comments') | |
39 | 45 | ) + |
40 | 46 | |
41 | 47 | (article.can_display_hits? ? | ... | ... |
... | ... | @@ -0,0 +1,70 @@ |
1 | +module CommentHelper | |
2 | + | |
3 | + def article_title(article, args = {}) | |
4 | + title = article.title | |
5 | + title = article.display_title if article.kind_of?(UploadedFile) && article.image? | |
6 | + title = content_tag('h1', h(title), :class => 'title') | |
7 | + if article.belongs_to_blog? | |
8 | + unless args[:no_link] | |
9 | + title = content_tag('h1', link_to(article.name, article.url), :class => 'title') | |
10 | + end | |
11 | + comments = '' | |
12 | + unless args[:no_comments] || !article.accept_comments | |
13 | + comments = (" - %s") % link_to_comments(article) | |
14 | + end | |
15 | + title << content_tag('span', | |
16 | + content_tag('span', show_date(article.published_at), :class => 'date') + | |
17 | + content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') + | |
18 | + content_tag('span', comments, :class => 'comments'), | |
19 | + :class => 'created-at' | |
20 | + ) | |
21 | + end | |
22 | + title | |
23 | + end | |
24 | + | |
25 | + def comment_actions(comment) | |
26 | + url = url_for(:profile => profile.identifier, :controller => :comment, :action => :check_actions, :id => comment.id) | |
27 | + links = links_for_comment_actions(comment) | |
28 | + content_tag(:li, link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger comment-trigger', :url => url), :class=> 'vcard') unless links.empty? | |
29 | + end | |
30 | + | |
31 | + private | |
32 | + | |
33 | + def links_for_comment_actions(comment) | |
34 | + actions = [link_for_report_abuse(comment), link_for_spam(comment), link_for_edit(comment), link_for_remove(comment)] | |
35 | + @plugins.dispatch(:comment_actions, comment).collect do |action| | |
36 | + actions << (action.kind_of?(Proc) ? self.instance_eval(&action) : action) | |
37 | + end | |
38 | + actions.flatten.compact | |
39 | + end | |
40 | + | |
41 | + def link_for_report_abuse(comment) | |
42 | + if comment.author | |
43 | + report_abuse_link = report_abuse(comment.author, :comment_link, comment) | |
44 | + {:link => report_abuse_link} if report_abuse_link | |
45 | + end | |
46 | + end | |
47 | + | |
48 | + def link_for_spam(comment) | |
49 | + if comment.can_be_marked_as_spam_by?(user) | |
50 | + if comment.spam? | |
51 | + {:link => link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:profile => profile.identifier, :mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide')} | |
52 | + else | |
53 | + {:link => link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :mark_as_spam, :id => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide')} | |
54 | + end | |
55 | + end | |
56 | + end | |
57 | + | |
58 | + def link_for_edit(comment) | |
59 | + if comment.can_be_updated_by?(user) | |
60 | + {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'colorbox')} | |
61 | + end | |
62 | + end | |
63 | + | |
64 | + def link_for_remove(comment) | |
65 | + if comment.can_be_destroyed_by?(user) | |
66 | + {:link => link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :destroy, :id => comment.id).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children')} | |
67 | + end | |
68 | + end | |
69 | + | |
70 | +end | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -5,11 +5,9 @@ module ContentViewerHelper |
5 | 5 | |
6 | 6 | def number_of_comments(article) |
7 | 7 | n = article.comments.without_spam.count |
8 | - if n == 0 | |
9 | - _('No comments yet') | |
10 | - else | |
11 | - n_('One comment', '<span class="comment-count">%{comments}</span> comments', n) % { :comments => n } | |
12 | - end | |
8 | + base_str = "<span class='comment-count hide'>#{n}</span>" | |
9 | + amount_str = n == 0 ? _('no comments yet') : (n == 1 ? _('One comment') : _('%s comments') % n) | |
10 | + base_str + "<span class='comment-count-write-out'>#{amount_str}</span>" | |
13 | 11 | end |
14 | 12 | |
15 | 13 | def article_title(article, args = {}) | ... | ... |
... | ... | @@ -0,0 +1,104 @@ |
1 | +class ApproveComment < Task | |
2 | + validates_presence_of :target_id | |
3 | + | |
4 | + settings_items :comment_attributes, :closing_statment | |
5 | + | |
6 | + validates_presence_of :comment_attributes | |
7 | + | |
8 | + def comment | |
9 | + @comment ||= Comment.new(JSON.parse(self.comment_attributes)) unless self.comment_attributes.nil? | |
10 | + end | |
11 | + | |
12 | + def requestor_name | |
13 | + requestor ? requestor.name : (comment.name || _('Anonymous')) | |
14 | + end | |
15 | + | |
16 | + def article | |
17 | + Article.find_by_id comment.source_id unless self.comment.nil? | |
18 | + end | |
19 | + | |
20 | + def article_name | |
21 | + article ? article.name : _("Article removed.") | |
22 | + end | |
23 | + | |
24 | + def perform | |
25 | + comment.save! | |
26 | + end | |
27 | + | |
28 | + def title | |
29 | + _("New comment to article") | |
30 | + end | |
31 | + | |
32 | + def icon | |
33 | + result = {:type => :defined_image, :src => '/images/icons-app/article-minor.png'} | |
34 | + result.merge!({:url => article.url}) if article | |
35 | + result | |
36 | + end | |
37 | + | |
38 | + def linked_subject | |
39 | + {:text => article_name, :url => article.url} if article | |
40 | + end | |
41 | + | |
42 | + def information | |
43 | + if article | |
44 | + if requestor | |
45 | + {:message => _('%{requestor} commented on the the article: %{linked_subject}.')} | |
46 | + else | |
47 | + { :message => _('%{requestor} commented on the the article: %{linked_subject}.'), | |
48 | + :variables => {:requestor => requestor_name} } | |
49 | + end | |
50 | + else | |
51 | + {:message => _("The article was removed.")} | |
52 | + end | |
53 | + end | |
54 | + | |
55 | + def accept_details | |
56 | + true | |
57 | + end | |
58 | + | |
59 | + def reject_details | |
60 | + true | |
61 | + end | |
62 | + | |
63 | + def default_decision | |
64 | + if article | |
65 | + 'skip' | |
66 | + else | |
67 | + 'reject' | |
68 | + end | |
69 | + end | |
70 | + | |
71 | + def accept_disabled? | |
72 | + article.blank? | |
73 | + end | |
74 | + | |
75 | + def target_notification_description | |
76 | + if article | |
77 | + _('%{requestor} wants to comment the article: %{article}.') % {:requestor => requestor_name, :article => article.name} | |
78 | + else | |
79 | + _('%{requestor} wanted to comment the article but it was removed.') % {:requestor => requestor_name} | |
80 | + end | |
81 | + end | |
82 | + | |
83 | + def target_notification_message | |
84 | + target_notification_description + "\n\n" + | |
85 | + _('You need to login on %{system} in order to approve or reject this comment.') % { :system => target.environment.name } | |
86 | + end | |
87 | + | |
88 | + def task_finished_message | |
89 | + if !closing_statment.blank? | |
90 | + _("Your comment to the article \"%{article}\" was approved. Here is the comment left by the admin who approved your comment:\n\n%{comment} ") % {:article => article_name, :comment => closing_statment} | |
91 | + else | |
92 | + _('Your request for comment the article "%{article}" was approved.') % {:article => article_name} | |
93 | + end | |
94 | + end | |
95 | + | |
96 | + def task_cancelled_message | |
97 | + message = _('Your request for commenting the article "%{article}" was rejected.') % {:article => article_name} | |
98 | + if !reject_explanation.blank? | |
99 | + message += " " + _("Here is the reject explanation left by the administrator who rejected your comment: \n\n%{reject_explanation}") % {:reject_explanation => reject_explanation} | |
100 | + end | |
101 | + message | |
102 | + end | |
103 | + | |
104 | +end | ... | ... |
app/models/article.rb
... | ... | @@ -65,6 +65,7 @@ class Article < ActiveRecord::Base |
65 | 65 | settings_items :display_hits, :type => :boolean, :default => true |
66 | 66 | settings_items :author_name, :type => :string, :default => "" |
67 | 67 | settings_items :allow_members_to_edit, :type => :boolean, :default => false |
68 | + settings_items :moderate_comments, :type => :boolean, :default => false | |
68 | 69 | settings_items :followers, :type => Array, :default => [] |
69 | 70 | |
70 | 71 | belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' |
... | ... | @@ -327,6 +328,14 @@ class Article < ActiveRecord::Base |
327 | 328 | @view_url ||= image? ? url.merge(:view => true) : url |
328 | 329 | end |
329 | 330 | |
331 | + def comment_url_structure(comment, action = :edit) | |
332 | + if comment.new_record? | |
333 | + profile.url.merge(:page => path.split("/"), :controller => :comment, :action => :create) | |
334 | + else | |
335 | + profile.url.merge(:page => path.split("/"), :controller => :comment, :action => action || :edit, :id => comment.id) | |
336 | + end | |
337 | + end | |
338 | + | |
330 | 339 | def allow_children? |
331 | 340 | true |
332 | 341 | end |
... | ... | @@ -489,6 +498,14 @@ class Article < ActiveRecord::Base |
489 | 498 | allow_post_content?(user) || user && allow_members_to_edit && user.is_member_of?(profile) |
490 | 499 | end |
491 | 500 | |
501 | + def moderate_comments? | |
502 | + moderate_comments == true | |
503 | + end | |
504 | + | |
505 | + def comments_updated | |
506 | + solr_save | |
507 | + end | |
508 | + | |
492 | 509 | def accept_category?(cat) |
493 | 510 | !cat.is_a?(ProductCategory) |
494 | 511 | end | ... | ... |
app/models/comment.rb
... | ... | @@ -34,7 +34,9 @@ class Comment < ActiveRecord::Base |
34 | 34 | |
35 | 35 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' |
36 | 36 | |
37 | - delegate :environment, :to => :source | |
37 | + def comment_root | |
38 | + (reply_of && reply_of.comment_root) || self | |
39 | + end | |
38 | 40 | |
39 | 41 | def action_tracker_target |
40 | 42 | self.article.profile |
... | ... | @@ -248,4 +250,22 @@ class Comment < ActiveRecord::Base |
248 | 250 | plugins.dispatch(:comment_marked_as_ham, self) |
249 | 251 | end |
250 | 252 | |
253 | + def need_moderation? | |
254 | + article.moderate_comments? && (author.nil? || article.author != author) | |
255 | + end | |
256 | + | |
257 | + def can_be_destroyed_by?(user) | |
258 | + return if user.nil? | |
259 | + user == author || user == profile || user.has_permission?(:moderate_comments, profile) | |
260 | + end | |
261 | + | |
262 | + def can_be_marked_as_spam_by?(user) | |
263 | + return if user.nil? | |
264 | + user == profile || user.has_permission?(:moderate_comments, profile) | |
265 | + end | |
266 | + | |
267 | + def can_be_updated_by?(user) | |
268 | + user.present? && user == author | |
269 | + end | |
270 | + | |
251 | 271 | end | ... | ... |
app/models/task.rb
... | ... | @@ -74,7 +74,7 @@ class Task < ActiveRecord::Base |
74 | 74 | end |
75 | 75 | |
76 | 76 | def self.all_types |
77 | - %w[Invitation EnterpriseActivation AddMember Ticket SuggestArticle AddFriend CreateCommunity AbuseComplaint ApproveArticle CreateEnterprise ChangePassword EmailActivation InviteFriend InviteMember] | |
77 | + %w[Invitation EnterpriseActivation AddMember Ticket SuggestArticle AddFriend CreateCommunity AbuseComplaint ApproveComment ApproveArticle CreateEnterprise ChangePassword EmailActivation InviteFriend InviteMember] | |
78 | 78 | end |
79 | 79 | |
80 | 80 | # this method finished the task. It calls #perform, which must be overriden | ... | ... |
... | ... | @@ -0,0 +1,84 @@ |
1 | +<li id="<%= comment.anchor %>" class="article-comment"> | |
2 | + <div class="article-comment-inner"> | |
3 | + | |
4 | + <div class="comment-content comment-logged-<%= comment.author ? 'in' : 'out' %> <%= 'comment-from-owner' if ( comment.author && (profile == comment.author) ) %>"> | |
5 | + | |
6 | + <% if comment.author %> | |
7 | + <%= link_to image_tag(profile_icon(comment.author, :minor)) + | |
8 | + content_tag('span', comment.author_name, :class => 'comment-info'), | |
9 | + comment.author.url, | |
10 | + :class => 'comment-picture', | |
11 | + :title => comment.author_name | |
12 | + %> | |
13 | + <% else %> | |
14 | + <% url_image, status_class = comment.author_id ? | |
15 | + [comment.removed_user_image, 'icon-user-removed'] : | |
16 | + [str_gravatar_url_for( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %> | |
17 | + | |
18 | + <%= link_to( | |
19 | + image_tag(url_image, :onerror=>'gravatarCommentFailback(this)', | |
20 | + 'data-gravatar'=>str_gravatar_url_for(comment.email, :size=>50)) + | |
21 | + content_tag('span', comment.author_name, :class => 'comment-info') + | |
22 | + content_tag('span', comment.message, | |
23 | + :class => 'comment-user-status ' + status_class), | |
24 | + gravatar_profile_url(comment.email), | |
25 | + :target => '_blank', | |
26 | + :class => 'comment-picture', | |
27 | + :title => '%s %s' % [comment.author_name, comment.message] | |
28 | + )%> | |
29 | + <% end %> | |
30 | + | |
31 | + <% comment_balloon do %> | |
32 | + | |
33 | + <div class="comment-details"> | |
34 | + <div class="comment-header"> | |
35 | + <ul> | |
36 | + <div class="comment-actions"> | |
37 | + <%= comment_actions(comment) %> | |
38 | + </div> | |
39 | + </ul> | |
40 | + <% unless comment.spam? %> | |
41 | + <%= link_to_function '', | |
42 | + "var f = add_comment_reply_form(this, %s); f.find('comment_title, textarea').val(''); return false" % comment.id, | |
43 | + :class => 'comment-footer comment-footer-link comment-footer-hide comment-actions-reply button', | |
44 | + :id => 'comment-reply-to-' + comment.id.to_s | |
45 | + %> | |
46 | + <% end %> | |
47 | + </div> | |
48 | + | |
49 | + <div class="comment-created-at"> | |
50 | + <%= show_time(comment.created_at) %> | |
51 | + </div> | |
52 | + <h4><%= comment.title.blank? && ' ' || comment.title %></h4> | |
53 | + <div class="comment-text"> | |
54 | + <p/> | |
55 | + <%= txt2html comment.body %> | |
56 | + </div> | |
57 | + </div> | |
58 | + | |
59 | + <div class="comment_reply post_comment_box closed" id="comment_reply_to_<%= comment.id %>"> | |
60 | + <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %> | |
61 | + <%= error_messages_for :comment %> | |
62 | + <script type="text/javascript"> | |
63 | + jQuery(function() { | |
64 | + document.location.href = '#<%= comment.anchor %>'; | |
65 | + add_comment_reply_form('#comment-reply-to-<%= comment.id %>', <%= comment.id %>); | |
66 | + }); | |
67 | + </script> | |
68 | + <% end %> | |
69 | + </div> | |
70 | + | |
71 | + <% end %> | |
72 | + | |
73 | + </div> | |
74 | + | |
75 | + <% unless comment.replies.blank? || comment.spam? %> | |
76 | + <ul class="comment-replies"> | |
77 | + <% comment.replies.each do |reply| %> | |
78 | + <%= render :partial => 'comment/comment', :locals => { :comment => reply } %> | |
79 | + <% end %> | |
80 | + </ul> | |
81 | + <% end %> | |
82 | + | |
83 | + </div> | |
84 | +</li> | ... | ... |
... | ... | @@ -0,0 +1,96 @@ |
1 | +<% edition_mode = (defined? edition_mode) ? edition_mode : false %> | |
2 | +<div class="<%= edition_mode ? '' : 'page-comment-form' %>"> | |
3 | + | |
4 | +<% focus_on = logged_in? ? 'title' : 'name' %> | |
5 | + | |
6 | + | |
7 | +<% if !edition_mode && !pass_without_comment_captcha? %> | |
8 | + <div id="recaptcha-container" style="display: none"> | |
9 | + <h3><%= _('Please type the two words below') %></h3> | |
10 | + <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> | |
11 | + <% button_bar do %> | |
12 | + <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %> | |
13 | + <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %> | |
14 | + <% end %> | |
15 | + </div> | |
16 | + | |
17 | + <script type="text/javascript"> | |
18 | + jQuery(document).bind('cbox_cleanup', function() { | |
19 | + jQuery('#recaptcha-container').hide(); | |
20 | + }); | |
21 | + </script> | |
22 | +<% end %> | |
23 | + | |
24 | +<script type="text/javascript"> | |
25 | +function check_captcha(button, confirm_action) { | |
26 | + <% if edition_mode %> | |
27 | + return true; | |
28 | + <% elsif pass_without_comment_captcha? %> | |
29 | + button.form.confirm.value = 'true'; | |
30 | + button.disabled = true; | |
31 | + return true; | |
32 | + <% else %> | |
33 | + jQuery('#recaptcha-container').show(); | |
34 | + jQuery.colorbox({ inline : true, href : '#recaptcha-container', maxWidth : '600px', maxHeight : '300px' }); | |
35 | + jQuery('#confirm-captcha').unbind('click'); | |
36 | + jQuery('#confirm-captcha').bind('click', function() { | |
37 | + jQuery.colorbox.close(); | |
38 | + button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val(); | |
39 | + button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val(); | |
40 | + button.form.confirm.value = 'true'; | |
41 | + button.disabled = false; | |
42 | + confirm_action(button); | |
43 | + }); | |
44 | + return false; | |
45 | + <% end %> | |
46 | +} | |
47 | +</script> | |
48 | + | |
49 | +<% if @comment && @comment.errors.any? %> | |
50 | + <%= error_messages_for :comment %> | |
51 | +<% end %> | |
52 | + | |
53 | +<div class="post_comment_box <%= ((defined? show_form) && show_form) ? 'opened' : 'closed' %>"> | |
54 | + | |
55 | + <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form') if display_link && @comment.reply_of_id.blank? %> | |
56 | +<% remote_form_for(:comment, comment, :url => {:profile => profile.identifier, :controller => 'comment', :action => (edition_mode ? 'update' : 'create'), :id => (edition_mode ? comment.id : @page.id)}, :html => { :class => 'comment_form' } ) do |f| %> | |
57 | + | |
58 | + <%= required_fields_message %> | |
59 | + | |
60 | + <% unless logged_in? %> | |
61 | + | |
62 | + <%= required labelled_form_field(_('Name'), f.text_field(:name)) %> | |
63 | + <%= required labelled_form_field(_('e-mail'), f.text_field(:email)) %> | |
64 | + <p> | |
65 | + <%= _('If you are a registered user, you can login and be automatically recognized.') %> | |
66 | + </p> | |
67 | + | |
68 | + <% end %> | |
69 | + | |
70 | + <% if !edition_mode && !pass_without_comment_captcha? %> | |
71 | + <%= hidden_field_tag(:recaptcha_response_field, nil, :id => nil) %> | |
72 | + <%= hidden_field_tag(:recaptcha_challenge_field, nil, :id => nil) %> | |
73 | + <% end %> | |
74 | + | |
75 | + <%= labelled_form_field(_('Title'), f.text_field(:title)) %> | |
76 | + <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> | |
77 | + | |
78 | + <%= hidden_field_tag(:confirm, 'false') %> | |
79 | + <%= hidden_field_tag(:view, params[:view])%> | |
80 | + <%= f.hidden_field(:reply_of_id) %> | |
81 | + | |
82 | + <% button_bar do %> | |
83 | + <%= submit_button('add', _('Post comment'), :onclick => "if(check_captcha(this)) { save_comment(this) } else { check_captcha(this, save_comment)};return false;") %> | |
84 | + <% if !edition_mode %> | |
85 | + <%= button :cancel, _('Cancel'), '', :id => 'cancel-comment' %> | |
86 | + <% else %> | |
87 | + <%= button :cancel, _('Cancel'), '#', :onclick => "jQuery.colorbox.close();" %> | |
88 | + <% end %> | |
89 | + <% end %> | |
90 | +<% end %> | |
91 | + | |
92 | + | |
93 | +</div><!-- end class="post_comment_box" --> | |
94 | +</div><!-- end class="page-comment-form" --> | |
95 | + | |
96 | +<%= javascript_include_tag 'comment_form'%> | ... | ... |
app/views/content_viewer/_comment.rhtml
... | ... | @@ -1,99 +0,0 @@ |
1 | -<li id="<%= comment.anchor %>" class="article-comment"> | |
2 | - <div class="article-comment-inner"> | |
3 | - | |
4 | - <div class="comment-content comment-logged-<%= comment.author ? 'in' : 'out' %> <%= 'comment-from-owner' if ( comment.author && (profile == comment.author) ) %>"> | |
5 | - | |
6 | - <% if comment.author %> | |
7 | - <%= link_to image_tag(profile_icon(comment.author, :minor)) + | |
8 | - content_tag('span', comment.author_name, :class => 'comment-info'), | |
9 | - comment.author.url, | |
10 | - :class => 'comment-picture', | |
11 | - :title => comment.author_name | |
12 | - %> | |
13 | - <% else %> | |
14 | - <% url_image, status_class = comment.author_id ? | |
15 | - [comment.removed_user_image, 'icon-user-removed'] : | |
16 | - [str_gravatar_url_for( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %> | |
17 | - | |
18 | - <%= link_to( | |
19 | - image_tag(url_image, :onerror=>'gravatarCommentFailback(this)', | |
20 | - 'data-gravatar'=>str_gravatar_url_for(comment.email, :size=>50)) + | |
21 | - content_tag('span', comment.author_name, :class => 'comment-info') + | |
22 | - content_tag('span', comment.message, | |
23 | - :class => 'comment-user-status ' + status_class), | |
24 | - gravatar_profile_url(comment.email), | |
25 | - :target => '_blank', | |
26 | - :class => 'comment-picture', | |
27 | - :title => '%s %s' % [comment.author_name, comment.message] | |
28 | - )%> | |
29 | - <% end %> | |
30 | - | |
31 | - <% comment_balloon do %> | |
32 | - | |
33 | - <div class="comment-details"> | |
34 | - <div class="comment-created-at"> | |
35 | - <%= show_time(comment.created_at) %> | |
36 | - </div> | |
37 | - <h4><%= comment.title.blank? && ' ' || comment.title %></h4> | |
38 | - <div class="comment-text"> | |
39 | - <p/> | |
40 | - <%= txt2html comment.body %> | |
41 | - </div> | |
42 | - </div> | |
43 | - | |
44 | - <div class="comment_reply post_comment_box closed"> | |
45 | - <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %> | |
46 | - <%= error_messages_for :comment %> | |
47 | - <script type="text/javascript"> | |
48 | - jQuery(function() { | |
49 | - document.location.href = '#<%= comment.anchor %>'; | |
50 | - add_comment_reply_form('#comment-reply-to-<%= comment.id %>', <%= comment.id %>); | |
51 | - }); | |
52 | - </script> | |
53 | - <% end %> | |
54 | - <%= report_abuse(comment.author, :comment_link, comment) if comment.author %> | |
55 | - | |
56 | - <% if comment.spam? %> | |
57 | - | |
58 | - <%= link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide') %> | |
59 | - <% else %> | |
60 | - <% if (logged_in? && (user == profile || user.has_permission?(:moderate_comments, profile))) %> | |
61 | - | |
62 | - <%= link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:mark_comment_as_spam => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide') %> | |
63 | - <% end %> | |
64 | - <% end %> | |
65 | - | |
66 | - <% if comment.author && comment.author == user %> | |
67 | - | |
68 | - <%= expirable_comment_link comment, :edit, _('Edit'), {:action => 'edit_comment', :id => comment.id, :profile => profile.identifier} %> | |
69 | - <% end %> | |
70 | - | |
71 | - <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %> | |
72 | - | |
73 | - <%= link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => params[:profile], :remove_comment => comment.id, :view => params[:view]).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children') %> | |
74 | - <% end %> | |
75 | - | |
76 | - <% unless comment.spam? %> | |
77 | - | |
78 | - <%= link_to_function _('Reply'), | |
79 | - "var f = add_comment_reply_form(this, %s); f.find('comment_title, textarea').val(''); return false" % comment.id, | |
80 | - :class => 'comment-footer comment-footer-link comment-footer-hide', | |
81 | - :id => 'comment-reply-to-' + comment.id.to_s | |
82 | - %> | |
83 | - <% end %> | |
84 | - </div> | |
85 | - | |
86 | - <% end %> | |
87 | - | |
88 | - </div> | |
89 | - | |
90 | - <% unless comment.replies.blank? || comment.spam? %> | |
91 | - <ul class="comment-replies"> | |
92 | - <% comment.replies.each do |reply| %> | |
93 | - <%= render :partial => 'comment', :locals => { :comment => reply } %> | |
94 | - <% end %> | |
95 | - </ul> | |
96 | - <% end %> | |
97 | - | |
98 | - </div> | |
99 | -</li> |
app/views/content_viewer/_comment_form.rhtml
... | ... | @@ -1,88 +0,0 @@ |
1 | -<script type="text/javascript"> | |
2 | -function submit_comment_form(button) { | |
3 | - <% if pass_without_comment_captcha? %> | |
4 | - button.form.confirm.value = 'true'; | |
5 | - button.disabled = true; | |
6 | - button.form.submit(); | |
7 | - return true; | |
8 | - <% else %> | |
9 | - jQuery('#recaptcha-container').show(); | |
10 | - jQuery.colorbox({ inline : true, href : '#recaptcha-container', maxWidth : '600px', maxHeight : '300px' }); | |
11 | - jQuery('#confirm-captcha').unbind('click'); | |
12 | - jQuery('#confirm-captcha').bind('click', function() { | |
13 | - jQuery.colorbox.close(); | |
14 | - button.form.recaptcha_response_field.value = jQuery('#recaptcha_response_field').val(); | |
15 | - button.form.recaptcha_challenge_field.value = jQuery('#recaptcha_challenge_field').val(); | |
16 | - button.form.confirm.value = 'true'; | |
17 | - button.disabled = true; | |
18 | - button.form.submit(); | |
19 | - }); | |
20 | - <% end %> | |
21 | -} | |
22 | -</script> | |
23 | - | |
24 | -<% if @comment && @comment.errors.any? && @comment.reply_of_id.blank? %> | |
25 | - <%= error_messages_for :comment %> | |
26 | - <script type="text/javascript">jQuery(function() { document.location.href = '#page-comment-form'; });</script> | |
27 | -<% end %> | |
28 | - | |
29 | -<% @form_div ||= 'closed' %> | |
30 | - | |
31 | -<div class="post_comment_box <%= @form_div %>"> | |
32 | - | |
33 | - <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form') if display_link %> | |
34 | - | |
35 | -<% unless pass_without_comment_captcha? %> | |
36 | - <div id="recaptcha-container" style="display: none"> | |
37 | - <h3><%= _('Please type the two words below') %></h3> | |
38 | - <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> | |
39 | - <% button_bar do %> | |
40 | - <%= button_to_function :add, _('Confirm'), "return false", :id => "confirm-captcha" %> | |
41 | - <%= button_to_function :cancel, _('Cancel'), "jQuery.colorbox.close()" %> | |
42 | - <% end %> | |
43 | - </div> | |
44 | - | |
45 | - <script type="text/javascript"> | |
46 | - jQuery(document).bind('cbox_cleanup', function() { | |
47 | - jQuery('#recaptcha-container').hide(); | |
48 | - }); | |
49 | - </script> | |
50 | -<% end %> | |
51 | - | |
52 | -<% form_tag( url, { :class => 'comment_form' } ) do %> | |
53 | - <%= required_fields_message %> | |
54 | - | |
55 | - <% unless logged_in? %> | |
56 | - | |
57 | - <%= required labelled_form_field(_('Name'), text_field(:comment, :name)) %> | |
58 | - <%= required labelled_form_field(_('e-mail'), text_field(:comment, :email)) %> | |
59 | - <p> | |
60 | - <%= _('If you are a registered user, you can login and be automatically recognized.') %> | |
61 | - </p> | |
62 | - | |
63 | - <% end %> | |
64 | - | |
65 | - <% unless pass_without_comment_captcha? %> | |
66 | - <%= hidden_field_tag(:recaptcha_response_field, nil, :id => nil) %> | |
67 | - <%= hidden_field_tag(:recaptcha_challenge_field, nil, :id => nil) %> | |
68 | - <% end %> | |
69 | - | |
70 | - <%= labelled_form_field(_('Title'), text_field(:comment, :title)) %> | |
71 | - <%= required labelled_form_field(_('Enter your comment'), text_area(:comment, :body, :rows => 5)) %> | |
72 | - | |
73 | - <%= hidden_field_tag(:confirm, 'false') %> | |
74 | - <%= hidden_field_tag(:view, params[:view])%> | |
75 | - | |
76 | - <% button_bar do %> | |
77 | - <%= submit_button('add', _('Post comment'), :onclick => "submit_comment_form(this); return false") %> | |
78 | - <% if cancel_triggers_hide %> | |
79 | - <%= button :cancel, _('Cancel'), '', :id => 'cancel-comment' %> | |
80 | - <% else %> | |
81 | - <%= button('cancel', _('Cancel'), {:action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path})%> | |
82 | - <% end %> | |
83 | - <% end %> | |
84 | -<% end %> | |
85 | - | |
86 | -</div><!-- end class="post_comment_box" --> | |
87 | - | |
88 | -<%= javascript_include_tag 'comment_form'%> |
app/views/content_viewer/edit_comment.html.erb
app/views/content_viewer/view_page.rhtml
... | ... | @@ -8,6 +8,12 @@ |
8 | 8 | |
9 | 9 | <%= render :partial => 'confirm_unfollow' %> |
10 | 10 | |
11 | +<script type="text/javascript"> | |
12 | + window.ONE_COMMENT = "<%= _('One comment') %>"; | |
13 | + window.COMMENT_PLURAL = "<%= _('comments') %>"; | |
14 | + window.NO_COMMENT_YET = "<%= _('No comments yet') %>"; | |
15 | +</script> | |
16 | + | |
11 | 17 | <div id="article-toolbar"></div> |
12 | 18 | |
13 | 19 | <script type="text/javascript"> |
... | ... | @@ -89,15 +95,15 @@ |
89 | 95 | <% end %> |
90 | 96 | |
91 | 97 | <% if @page.accept_comments? && @comments_count > 1 %> |
92 | - <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form', :id => 'top-post-comment-button') %> | |
98 | + <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form', :id => 'top-post-comment-button', :onclick => "jQuery('#page-comment-form .display-comment-form').first().click();") %> | |
93 | 99 | <% end %> |
94 | 100 | |
95 | 101 | <ul class="article-comments-list"> |
96 | - <%= render :partial => 'comment', :collection => @comments %> | |
102 | + <%= render :partial => 'comment/comment', :collection => @comments %> | |
97 | 103 | </ul> |
98 | 104 | |
99 | 105 | <% if @page.accept_comments? %> |
100 | - <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> | |
106 | + <div id='page-comment-form' class='page-comment-form'><%= render :partial => 'comment/comment_form', :locals =>{:comment => Comment.new, :url => {:controller => :comment, :action => :create}, :display_link => true, :cancel_triggers_hide => true}%></div> | |
101 | 107 | <% end %> |
102 | 108 | </div><!-- end class="comments" --> |
103 | 109 | ... | ... |
app/views/layouts/application-ng.rhtml
... | ... | @@ -17,6 +17,10 @@ |
17 | 17 | content.respond_to?(:call) ? content.call : content |
18 | 18 | end.join("\n") |
19 | 19 | %> |
20 | + | |
21 | + <script type='text/javascript'> | |
22 | + DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>; | |
23 | + </script> | |
20 | 24 | </head> |
21 | 25 | <body class="<%= body_classes %>"> |
22 | 26 | <a href="#content" id="link-go-content"><span><%= _("Go to the content") %></span></a> | ... | ... |
app/views/spam/index.rhtml
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | <div id='article'> |
9 | 9 | <div class="comments" id="comments_list"> |
10 | 10 | <ul class="article-comments-list"> |
11 | - <%= render :partial => 'content_viewer/comment', :collection => @spam %> | |
11 | + <%= render :partial => 'comment/comment', :collection => @spam %> | |
12 | 12 | </ul> |
13 | 13 | </div> |
14 | 14 | </div> | ... | ... |
config/routes.rb
... | ... | @@ -76,6 +76,9 @@ ActionController::Routing::Routes.draw do |map| |
76 | 76 | # profile search |
77 | 77 | map.profile_search 'profile/:profile/search', :controller => 'profile_search', :action => 'index', :profile => /#{Noosfero.identifier_format}/ |
78 | 78 | |
79 | + # comments | |
80 | + map.comment 'profile/:profile/comment/:action/:id', :controller => 'comment', :profile => /#{Noosfero.identifier_format}/ | |
81 | + | |
79 | 82 | # public profile information |
80 | 83 | map.profile 'profile/:profile/:action/:id', :controller => 'profile', :action => 'index', :id => /[^\/]*/, :profile => /#{Noosfero.identifier_format}/ |
81 | 84 | |
... | ... | @@ -122,7 +125,6 @@ ActionController::Routing::Routes.draw do |map| |
122 | 125 | # cache stuff - hack |
123 | 126 | map.cache 'public/:action/:id', :controller => 'public' |
124 | 127 | |
125 | - map.connect ':profile/edit_comment/:id/*page', :controller => 'content_viewer', :action => 'edit_comment', :profile => /#{Noosfero.identifier_format}/ | |
126 | 128 | |
127 | 129 | # match requests for profiles that don't have a custom domain |
128 | 130 | map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } | ... | ... |
lib/noosfero/plugin.rb
... | ... | @@ -320,6 +320,30 @@ class Noosfero::Plugin |
320 | 320 | def comment_marked_as_ham(comment) |
321 | 321 | end |
322 | 322 | |
323 | + # Adds extra actions for comments | |
324 | + # returns = list of hashes or lambda block that creates a list of hashes | |
325 | + # example: | |
326 | + # | |
327 | + # def comment_actions(comment) | |
328 | + # [{:link => link_to_function(...)}] | |
329 | + # end | |
330 | + # | |
331 | + def comment_actions(comment) | |
332 | + nil | |
333 | + end | |
334 | + | |
335 | + # This method is called when the user click on comment actions menu. | |
336 | + # returns = list or lambda block that return ids of enabled menu items for comments | |
337 | + # example: | |
338 | + # | |
339 | + # def check_comment_actions(comment) | |
340 | + # ['#action1', '#action2'] | |
341 | + # end | |
342 | + # | |
343 | + def check_comment_actions(comment) | |
344 | + [] | |
345 | + end | |
346 | + | |
323 | 347 | # -> Adds fields to the signup form |
324 | 348 | # returns = lambda block that creates html code |
325 | 349 | def signup_extra_contents | ... | ... |
plugins/require_auth_to_comment/lib/require_auth_to_comment_plugin.rb
plugins/require_auth_to_comment/public/hide_comment_form.js
1 | 1 | (function($) { |
2 | 2 | $(window).bind('userDataLoaded', function(event, data) { |
3 | - if (data.login || $('meta[name="profile.allow_unauthenticated_comments"]').length > 0) { | |
4 | - $('.post-comment-button').show(); | |
5 | - $('#page-comment-form').show(); | |
6 | - $('.comment-footer').show(); | |
3 | + if (data.login || $('meta[name=profile.allow_unauthenticated_comments]').length > 0) { | |
4 | + $('.post-comment-button').livequery(function() { | |
5 | + $(this).show(); | |
6 | + }); | |
7 | + $('.page-comment-form').livequery(function() { | |
8 | + $(this).show(); | |
9 | + }); | |
10 | + $('.comment-footer').livequery(function() { | |
11 | + $(this).show(); | |
12 | + }); | |
7 | 13 | } |
8 | 14 | }); |
9 | 15 | })(jQuery); | ... | ... |
plugins/require_auth_to_comment/public/jquery.livequery.min.js
0 → 100644
... | ... | @@ -0,0 +1,9 @@ |
1 | +/* Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) | |
2 | + * Dual licensed under the MIT (MIT_LICENSE.txt) | |
3 | + * and GPL Version 2 (GPL_LICENSE.txt) licenses. | |
4 | + * | |
5 | + * Version: 1.1.1 | |
6 | + * Requires jQuery 1.3+ | |
7 | + * Docs: http://docs.jquery.com/Plugins/livequery | |
8 | + */ | |
9 | +(function(a){a.extend(a.fn,{livequery:function(e,d,c){var b=this,f;if(a.isFunction(e)){c=d,d=e,e=undefined}a.each(a.livequery.queries,function(g,h){if(b.selector==h.selector&&b.context==h.context&&e==h.type&&(!d||d.$lqguid==h.fn.$lqguid)&&(!c||c.$lqguid==h.fn2.$lqguid)){return(f=h)&&false}});f=f||new a.livequery(this.selector,this.context,e,d,c);f.stopped=false;f.run();return this},expire:function(e,d,c){var b=this;if(a.isFunction(e)){c=d,d=e,e=undefined}a.each(a.livequery.queries,function(f,g){if(b.selector==g.selector&&b.context==g.context&&(!e||e==g.type)&&(!d||d.$lqguid==g.fn.$lqguid)&&(!c||c.$lqguid==g.fn2.$lqguid)&&!this.stopped){a.livequery.stop(g.id)}});return this}});a.livequery=function(b,d,f,e,c){this.selector=b;this.context=d;this.type=f;this.fn=e;this.fn2=c;this.elements=[];this.stopped=false;this.id=a.livequery.queries.push(this)-1;e.$lqguid=e.$lqguid||a.livequery.guid++;if(c){c.$lqguid=c.$lqguid||a.livequery.guid++}return this};a.livequery.prototype={stop:function(){var b=this;if(this.type){this.elements.unbind(this.type,this.fn)}else{if(this.fn2){this.elements.each(function(c,d){b.fn2.apply(d)})}}this.elements=[];this.stopped=true},run:function(){if(this.stopped){return}var d=this;var e=this.elements,c=a(this.selector,this.context),b=c.not(e);this.elements=c;if(this.type){b.bind(this.type,this.fn);if(e.length>0){a.each(e,function(f,g){if(a.inArray(g,c)<0){a.event.remove(g,d.type,d.fn)}})}}else{b.each(function(){d.fn.apply(this)});if(this.fn2&&e.length>0){a.each(e,function(f,g){if(a.inArray(g,c)<0){d.fn2.apply(g)}})}}}};a.extend(a.livequery,{guid:0,queries:[],queue:[],running:false,timeout:null,checkQueue:function(){if(a.livequery.running&&a.livequery.queue.length){var b=a.livequery.queue.length;while(b--){a.livequery.queries[a.livequery.queue.shift()].run()}}},pause:function(){a.livequery.running=false},play:function(){a.livequery.running=true;a.livequery.run()},registerPlugin:function(){a.each(arguments,function(c,d){if(!a.fn[d]){return}var b=a.fn[d];a.fn[d]=function(){var e=b.apply(this,arguments);a.livequery.run();return e}})},run:function(b){if(b!=undefined){if(a.inArray(b,a.livequery.queue)<0){a.livequery.queue.push(b)}}else{a.each(a.livequery.queries,function(c){if(a.inArray(c,a.livequery.queue)<0){a.livequery.queue.push(c)}})}if(a.livequery.timeout){clearTimeout(a.livequery.timeout)}a.livequery.timeout=setTimeout(a.livequery.checkQueue,20)},stop:function(b){if(b!=undefined){a.livequery.queries[b].stop()}else{a.each(a.livequery.queries,function(c){a.livequery.queries[c].stop()})}}});a.livequery.registerPlugin("append","prepend","after","before","wrap","attr","removeAttr","addClass","removeClass","toggleClass","empty","remove","html");a(function(){a.livequery.play()})})(jQuery); | |
0 | 10 | \ No newline at end of file | ... | ... |
plugins/require_auth_to_comment/public/style.css
public/designs/themes/base/style.css
public/javascripts/add-and-join.js
... | ... | @@ -100,4 +100,24 @@ jQuery(function($) { |
100 | 100 | clicked.parent().find(".send-an-email").fadeOut(); |
101 | 101 | }) |
102 | 102 | }) |
103 | + | |
104 | + $(".comment-trigger").live('click', function(){ | |
105 | + clicked = $(this); | |
106 | + url = clicked.attr("url"); | |
107 | + $.get(url, function(data){ | |
108 | + ids = []; | |
109 | + if(data && data.ids) { | |
110 | + for(var i=0; i<data.ids.length; i++) { | |
111 | + clicked.parent().find(data.ids[i]).fadeIn(); | |
112 | + ids.push(data.ids[i]); | |
113 | + } | |
114 | + } | |
115 | + clicked.parent().find('.comment-action-extra').each(function() { | |
116 | + if($.inArray('#'+$(this).attr('id'), ids)) | |
117 | + $(this).fadeOut(); | |
118 | + }); | |
119 | + }) | |
120 | + return false; | |
121 | + }) | |
122 | + | |
103 | 123 | }); | ... | ... |
public/javascripts/application.js
... | ... | @@ -79,6 +79,27 @@ function updateUrlField(name_field, id) { |
79 | 79 | } |
80 | 80 | } |
81 | 81 | |
82 | + | |
83 | + | |
84 | +jQuery.fn.centerInForm = function () { | |
85 | + var $ = jQuery; | |
86 | + var form = $(this).parent('form'); | |
87 | + this.css("position", "absolute"); | |
88 | + this.css("top", (form.height() - this.height())/ 2 + form.scrollTop() + "px"); | |
89 | + this.css("left", (form.width() - this.width()) / 2 + form.scrollLeft() + "px"); | |
90 | + this.css("width", form.width() + "px"); | |
91 | + this.css("height", form.height() + "px"); | |
92 | + return this; | |
93 | +} | |
94 | + | |
95 | +jQuery.fn.center = function () { | |
96 | + var $ = jQuery; | |
97 | + this.css("position", "absolute"); | |
98 | + this.css("top", ($(window).height() - this.height())/ 2 + $(window).scrollTop() + "px"); | |
99 | + this.css("left", ($(window).width() - this.width()) / 2 + $(window).scrollLeft() + "px"); | |
100 | + return this; | |
101 | +} | |
102 | + | |
82 | 103 | function show_warning(field, message) { |
83 | 104 | new Effect.Highlight(field, {duration:3}); |
84 | 105 | $(message).show(); |
... | ... | @@ -146,8 +167,9 @@ function loading_done(element_id) { |
146 | 167 | jQuery(element_id).removeClass('small-loading-dark'); |
147 | 168 | } |
148 | 169 | function open_loading(message) { |
149 | - jQuery('body').append("<div id='overlay_loading' class='ui-widget-overlay' style='display: none'/><div id='overlay_loading_modal' style='display: none'><p>"+message+"</p><img src='/images/loading-dark.gif'/></div>"); | |
170 | + jQuery('body').prepend("<div id='overlay_loading' class='ui-widget-overlay' style='display: none'/><div id='overlay_loading_modal' style='display: none'><p>"+message+"</p><img src='/images/loading-dark.gif'/></div>"); | |
150 | 171 | jQuery('#overlay_loading').show(); |
172 | + jQuery('#overlay_loading_modal').center(); | |
151 | 173 | jQuery('#overlay_loading_modal').fadeIn('slow'); |
152 | 174 | } |
153 | 175 | function close_loading() { |
... | ... | @@ -292,11 +314,17 @@ function toggleSubmenu(trigger, title, link_list) { |
292 | 314 | content.append('<h4>' + title + '</h4>'); |
293 | 315 | jQuery.each(link_list, function(index, link_hash) { |
294 | 316 | for (label in link_hash) { |
295 | - options = ""; | |
296 | - jQuery.each(link_hash[label], function(option, value){ | |
297 | - options += option +'="'+ value + '" '; | |
298 | - }) | |
299 | - list.append('<li><a '+ options +'>' + label + '</a></li>'); | |
317 | + if(link_hash[label]!=null) { | |
318 | + if(label=='link' && jQuery.type(link_hash[label])=="string") { | |
319 | + list.append('<li>' + link_hash[label] + '</li>'); | |
320 | + } else { | |
321 | + options = ""; | |
322 | + jQuery.each(link_hash[label], function(option, value){ | |
323 | + options += option +'="'+ value + '" '; | |
324 | + }) | |
325 | + list.append('<li><a '+ options +'>' + label + '</a></li>'); | |
326 | + } | |
327 | + } | |
300 | 328 | } |
301 | 329 | }); |
302 | 330 | content.append(list); |
... | ... | @@ -320,9 +348,9 @@ function hideAllSubmenus() { |
320 | 348 | // Hide visible ballons when clicked outside them |
321 | 349 | jQuery(document).ready(function() { |
322 | 350 | jQuery('body').live('click', function() { hideAllSubmenus(); }); |
323 | - jQuery('.menu-submenu-trigger').click(function(e) { e.stopPropagation(); }); | |
324 | - jQuery('.simplemenu-trigger').click(function(e) { e.stopPropagation(); }); | |
325 | - jQuery('#chat-online-users').click(function(e) { e.stopPropagation(); }); | |
351 | + jQuery('.menu-submenu-trigger').live('click', function(e) { e.stopPropagation(); }); | |
352 | + jQuery('.simplemenu-trigger').live('click', function(e) { e.stopPropagation(); }); | |
353 | + jQuery('#chat-online-users').live('click', function(e) { e.stopPropagation(); }); | |
326 | 354 | }); |
327 | 355 | |
328 | 356 | function input_javascript_ordering_stuff() { |
... | ... | @@ -688,22 +716,51 @@ jQuery(function($) { |
688 | 716 | }); |
689 | 717 | |
690 | 718 | function add_comment_reply_form(button, comment_id) { |
691 | - var container = jQuery(button).parents('.comment_reply'); | |
719 | + //var container = jQuery(button).parents('.comment_reply'); | |
720 | + var container = jQuery('#comment_reply_to_'+comment_id); | |
692 | 721 | var f = container.find('.comment_form'); |
693 | 722 | if (f.length == 0) { |
694 | - f = jQuery('#page-comment-form .comment_form').clone(); | |
695 | - f.find('.fieldWithErrors').map(function() { jQuery(this).replaceWith(jQuery(this).contents()); }); | |
696 | - f.prepend('<input type="hidden" name="comment[reply_of_id]" value="' + comment_id + '" />'); | |
697 | - container.append(f); | |
723 | + comments_div = jQuery(button).parents('.comments'); | |
724 | + f = comments_div.find('.comment_form').first().clone(); | |
725 | + f.find('.errorExplanation').remove(); | |
726 | + f.append('<input type="hidden" name="comment[reply_of_id]" value="' + comment_id + '" />'); | |
727 | + container.append('<div class="page-comment-form"></div>'); | |
728 | + container.find('.page-comment-form').append(f); | |
698 | 729 | } |
699 | 730 | if (container.hasClass('closed')) { |
700 | 731 | container.removeClass('closed'); |
701 | 732 | container.addClass('opened'); |
702 | 733 | container.find('.comment_form input[type=text]:visible:first').focus(); |
703 | 734 | } |
735 | + jQuery('.display-comment-form').hide(); | |
704 | 736 | return f; |
705 | 737 | } |
706 | 738 | |
739 | +function update_comment_count(element, new_count) { | |
740 | + var $ = jQuery; | |
741 | + var content = ''; | |
742 | + var parent_element = element.parent(); | |
743 | + | |
744 | + write_out = parent_element.find('.comment-count-write-out'); | |
745 | + | |
746 | + element.html(new_count); | |
747 | + | |
748 | + if(new_count == 0) { | |
749 | + content = NO_COMMENT_YET; | |
750 | + parent_element.addClass("no-comments-yet"); | |
751 | + } else if(new_count == 1) { | |
752 | + parent_element.removeClass("no-comments-yet"); | |
753 | + content = ONE_COMMENT; | |
754 | + } else { | |
755 | + content = new_count + ' ' + COMMENT_PLURAL; | |
756 | + } | |
757 | + | |
758 | + if(write_out){ | |
759 | + write_out.html(content); | |
760 | + } | |
761 | + | |
762 | +} | |
763 | + | |
707 | 764 | function remove_comment(button, url, msg) { |
708 | 765 | var $ = jQuery; |
709 | 766 | var $button = $(button); |
... | ... | @@ -716,17 +773,27 @@ function remove_comment(button, url, msg) { |
716 | 773 | if (data.ok) { |
717 | 774 | var $comment = $button.closest('.article-comment'); |
718 | 775 | var $replies = $comment.find('.comment-replies .article-comment'); |
719 | - $comment.slideUp(); | |
776 | + | |
777 | + var $comments_div = $button.closest('.comments'); | |
778 | + | |
720 | 779 | var comments_removed = 1; |
721 | - if ($button.hasClass('remove-children')) { | |
722 | - comments_removed = 1 + $replies.size(); | |
723 | - } else { | |
724 | - $replies.appendTo('.article-comments-list'); | |
725 | - } | |
726 | - $('.comment-count').each(function() { | |
727 | - var count = parseInt($(this).html()); | |
728 | - $(this).html(count - comments_removed); | |
780 | + $comment.slideUp(400, function() { | |
781 | + if ($button.hasClass('remove-children')) { | |
782 | + comments_removed = 1 + $replies.size(); | |
783 | + } else { | |
784 | + $replies.appendTo('.article-comments-list'); | |
785 | + } | |
786 | + | |
787 | + $comments_div.find('.comment-count').add('#article-header .comment-count').each(function() { | |
788 | + var count = parseInt($(this).html()); | |
789 | + update_comment_count($(this), count - comments_removed); | |
790 | + }); | |
791 | + $(this).remove(); | |
729 | 792 | }); |
793 | + | |
794 | + }else{ | |
795 | + $button.removeClass('comment-button-loading'); | |
796 | + return; | |
730 | 797 | } |
731 | 798 | }); |
732 | 799 | } | ... | ... |
public/javascripts/comment_form.js
1 | +jQuery('.display-comment-form').unbind(); | |
1 | 2 | jQuery('.display-comment-form').click(function(){ |
2 | - toggleBox('.post_comment_box'); | |
3 | + var $button = jQuery(this); | |
4 | + toggleBox($button.parents('.post_comment_box')); | |
3 | 5 | jQuery('.display-comment-form').hide(); |
4 | - jQuery('form.comment_form input').first().focus(); | |
6 | + $button.closest('.page-comment-form').find('input').first().focus(); | |
5 | 7 | return false; |
6 | 8 | }); |
7 | 9 | |
8 | -jQuery('#cancel-comment').click(function(){ | |
9 | - toggleBox('.post_comment_box'); | |
10 | - jQuery('.display-comment-form').show(); | |
11 | - return false | |
12 | -}) | |
10 | +jQuery('#cancel-comment').die(); | |
11 | +jQuery('#cancel-comment').live("click", function(){ | |
12 | + var $button = jQuery(this); | |
13 | + toggleBox($button.parents('.post_comment_box')); | |
14 | + show_display_comment_button(); | |
15 | + var page_comment_form = $button.parents('.page-comment-form'); | |
16 | + page_comment_form.find('.errorExplanation').remove(); | |
17 | + return false; | |
18 | +}); | |
13 | 19 | |
14 | -function toggleBox(div_selector){ | |
15 | - div = jQuery(div_selector); | |
20 | +function toggleBox(div){ | |
16 | 21 | if(div.hasClass('opened')) { |
17 | 22 | div.removeClass('opened'); |
18 | 23 | div.addClass('closed'); |
... | ... | @@ -21,3 +26,67 @@ function toggleBox(div_selector){ |
21 | 26 | div.addClass('opened'); |
22 | 27 | } |
23 | 28 | } |
29 | + | |
30 | +function save_comment(button) { | |
31 | + var $ = jQuery; | |
32 | + open_loading(DEFAULT_LOADING_MESSAGE); | |
33 | + var $button = $(button); | |
34 | + var form = $button.parents("form"); | |
35 | + var post_comment_box = $button.parents('.post_comment_box'); | |
36 | + var comment_div = $button.parents('.comments'); | |
37 | + var page_comment_form = $button.parents('.page-comment-form'); | |
38 | + $button.addClass('comment-button-loading'); | |
39 | + $.post(form.attr("action"), form.serialize(), function(data) { | |
40 | + | |
41 | + if(data.render_target == null) { | |
42 | + //Comment for approval | |
43 | + form.find("input[type='text']").add('textarea').each(function() { | |
44 | + this.value = ''; | |
45 | + }); | |
46 | + page_comment_form.find('.errorExplanation').remove(); | |
47 | + } else if(data.render_target == 'form') { | |
48 | + //Comment with errors | |
49 | + $.scrollTo(page_comment_form); | |
50 | + page_comment_form.html(data.html); | |
51 | + $('.display-comment-form').hide(); | |
52 | + } else if($('#' + data.render_target).size() > 0) { | |
53 | + //Comment of reply | |
54 | + $('#'+ data.render_target).replaceWith(data.html); | |
55 | + $('#' + data.render_target).effect("highlight", {}, 3000); | |
56 | + $.colorbox.close(); | |
57 | + } else { | |
58 | + //New comment of article | |
59 | + comment_div.find('.article-comments-list').append(data.html); | |
60 | + | |
61 | + form.find("input[type='text']").add('textarea').each(function() { | |
62 | + this.value = ''; | |
63 | + }); | |
64 | + | |
65 | + page_comment_form.find('.errorExplanation').remove(); | |
66 | + $.colorbox.close(); | |
67 | + } | |
68 | + | |
69 | + comment_div.find('.comment-count').add('#article-header .comment-count').each(function() { | |
70 | + var count = parseInt($(this).html()); | |
71 | + update_comment_count($(this), count + 1); | |
72 | + }); | |
73 | + | |
74 | + if(jQuery('#recaptcha_response_field').val()){ | |
75 | + Recaptcha.reload(); | |
76 | + } | |
77 | + | |
78 | + if(data.msg != null) { | |
79 | + display_notice(data.msg); | |
80 | + } | |
81 | + close_loading(); | |
82 | + toggleBox($button.closest('.post_comment_box')); | |
83 | + show_display_comment_button(); | |
84 | + $button.removeClass('comment-button-loading'); | |
85 | + $button.enable(); | |
86 | + }, 'json'); | |
87 | +} | |
88 | + | |
89 | +function show_display_comment_button() { | |
90 | + if(jQuery('.post_comment_box.opened').length==0) | |
91 | + jQuery('.display-comment-form').show(); | |
92 | +} | ... | ... |
public/stylesheets/application.css
... | ... | @@ -528,11 +528,15 @@ code input { |
528 | 528 | background: transparent url(../images/loading-small-dark.gif) no-repeat 10% center; |
529 | 529 | } |
530 | 530 | #overlay_loading { |
531 | - z-index: 100; | |
532 | - cursor: progress; | |
531 | + z-index: 10000; | |
532 | + top: 0; | |
533 | + left: 0; | |
534 | + position: fixed; | |
535 | + width: 100%; | |
536 | + height: 100%; | |
533 | 537 | } |
534 | 538 | #overlay_loading_modal { |
535 | - z-index: 101; | |
539 | + z-index: 10001; | |
536 | 540 | width: 160px; |
537 | 541 | height: 120px; |
538 | 542 | border: 1px solid #000; |
... | ... | @@ -998,6 +1002,9 @@ code input { |
998 | 1002 | |
999 | 1003 | .comments { |
1000 | 1004 | } |
1005 | +span.comment-count.hide{ | |
1006 | + display: none; | |
1007 | +} | |
1001 | 1008 | #content .no-comments-yet { |
1002 | 1009 | text-align: center; |
1003 | 1010 | font-size: 80%; |
... | ... | @@ -1018,7 +1025,7 @@ code input { |
1018 | 1025 | margin-bottom: 10px; |
1019 | 1026 | padding: 4px; |
1020 | 1027 | } |
1021 | -#article .article-comment h4 { | |
1028 | +#article .article-comment .comment-details h4 { | |
1022 | 1029 | font-size: 13px; |
1023 | 1030 | margin: 0px; |
1024 | 1031 | display: inline; |
... | ... | @@ -1291,6 +1298,10 @@ a.comment-picture { |
1291 | 1298 | -webkit-border-radius: 4px; |
1292 | 1299 | border-radius: 4px; |
1293 | 1300 | } |
1301 | +.post_comment_box.opened h4 { | |
1302 | + border: none; | |
1303 | + cursor: default; | |
1304 | +} | |
1294 | 1305 | .post_comment_box.opened { |
1295 | 1306 | border: 1px solid #888; |
1296 | 1307 | background: #eee; |
... | ... | @@ -1341,6 +1352,11 @@ a.comment-picture { |
1341 | 1352 | .post_comment_box.comment_reply #comment_title { |
1342 | 1353 | width: 100%; |
1343 | 1354 | } |
1355 | + | |
1356 | +#page-comment-form-template { | |
1357 | + display:none; | |
1358 | +} | |
1359 | + | |
1344 | 1360 | #page-comment-form .post_comment_box { |
1345 | 1361 | text-align: left; |
1346 | 1362 | padding-left: 0; |
... | ... | @@ -1656,13 +1672,15 @@ a.button.disabled, input.disabled { |
1656 | 1672 | * Block options editor floating window * |
1657 | 1673 | ****************************************/ |
1658 | 1674 | |
1675 | +/* FIXME This changes broke colorboxes all over the place. | |
1676 | + * Therefore I'm canceling them until they are properly treateda. */ | |
1659 | 1677 | #cboxLoadedContent { |
1660 | 1678 | background: #FFF; |
1661 | - box-shadow: 0 0 15px #888 inset; | |
1662 | - border-radius: 5px; | |
1663 | - border: 1px solid #777; | |
1664 | - border-left: none; | |
1665 | - border-right: none; | |
1679 | +/* box-shadow: 0 0 15px #888 inset; | |
1680 | + border-radius: 5px; | |
1681 | + border: 1px solid #777; | |
1682 | + border-left: none; | |
1683 | + border-right: none; */ | |
1666 | 1684 | } |
1667 | 1685 | |
1668 | 1686 | .block-config-options { |
... | ... | @@ -1786,13 +1804,32 @@ a.button.disabled, input.disabled { |
1786 | 1804 | #content .profile-list-block ul { |
1787 | 1805 | width: 200px; |
1788 | 1806 | } |
1789 | -#content .common-profile-list-block li { | |
1790 | - margin: 0px; | |
1807 | +#content .comment-header .comment-actions-reply { | |
1808 | + float: right; | |
1809 | + background-image: url(/designs/icons/tango/Tango/16x16/actions/go-jump.png); | |
1810 | + height: 12px; | |
1811 | +} | |
1812 | +#content .comment-header ul { | |
1813 | + float: right; | |
1814 | + margin: 1px 0px 14px 0px; | |
1815 | +} | |
1816 | +#content .comment-actions .menu-submenu-header, #content .comment-actions .menu-submenu-footer, #content .comment-actions .menu-submenu h4 { | |
1817 | + display: none; | |
1818 | +} | |
1819 | +#content .comment-actions .menu-submenu ul { | |
1820 | + border: 1px solid #888a85; | |
1821 | + background-color: #efefef; | |
1822 | + padding-right: 2px; | |
1823 | + height: auto; | |
1824 | + display: block; | |
1825 | +} | |
1826 | +#content .common-profile-list-block li, #content .comment-actions li { | |
1827 | + margin: 0px !important; | |
1791 | 1828 | padding: 0px; |
1792 | 1829 | list-style: none; |
1793 | 1830 | position: relative; |
1794 | 1831 | } |
1795 | -.common-profile-list-block .vcard a { | |
1832 | +.common-profile-list-block .vcard a, .comment-actions .vcard a { | |
1796 | 1833 | display: block; |
1797 | 1834 | height: 112px; |
1798 | 1835 | max-height: 112px; |
... | ... | @@ -1803,7 +1840,7 @@ a.button.disabled, input.disabled { |
1803 | 1840 | text-align: center; |
1804 | 1841 | overflow: hidden; |
1805 | 1842 | font-size: 11px; |
1806 | - text-decoration: none; | |
1843 | + text-decoration: none !important; | |
1807 | 1844 | color: #000; |
1808 | 1845 | position: relative; |
1809 | 1846 | cursor: pointer; /* work arround bug for MSIE */ |
... | ... | @@ -4559,11 +4596,17 @@ h1#agenda-title { |
4559 | 4596 | } |
4560 | 4597 | /* Profile balloon */ |
4561 | 4598 | |
4562 | -.common-profile-list-block .vcard { | |
4599 | +.common-profile-list-block .vcard, .comment-actions .vcard { | |
4563 | 4600 | position: relative !important; |
4564 | 4601 | float: left; |
4565 | 4602 | } |
4566 | -.common-profile-list-block .vcard .menu-submenu-trigger, .menu-submenu-trigger { | |
4603 | +#content .comment-actions .vcard { | |
4604 | + padding-right: 20px; | |
4605 | +} | |
4606 | +#content .comment-actions .vcard .menu-submenu-trigger { | |
4607 | + display: block; | |
4608 | +} | |
4609 | +.common-profile-list-block .vcard .menu-submenu-trigger, .menu-submenu-trigger, .comment-actions .vcard .menu-submenu-trigger { | |
4567 | 4610 | display: none; |
4568 | 4611 | width: 16px; |
4569 | 4612 | height: 16px; |
... | ... | @@ -4577,7 +4620,7 @@ h1#agenda-title { |
4577 | 4620 | -moz-border-radius: 5px; |
4578 | 4621 | -webkit-border-radius: 5px; |
4579 | 4622 | } |
4580 | -.common-profile-list-block .vcard .menu-submenu-trigger:hover, .menu-submenu-trigger:hover { | |
4623 | +.common-profile-list-block .vcard .menu-submenu-trigger:hover, .menu-submenu-trigger:hover, .comment-actions .vcard .menu-submenu-trigger:hover { | |
4581 | 4624 | background: #fff url(/images/top-arrow.png) center center no-repeat; |
4582 | 4625 | border: 1px solid #ccc; |
4583 | 4626 | } |
... | ... | @@ -4596,6 +4639,10 @@ h1#agenda-title { |
4596 | 4639 | padding: 0; |
4597 | 4640 | text-align: left; |
4598 | 4641 | } |
4642 | +.comment-details .menu-submenu { | |
4643 | + bottom: 0px; | |
4644 | + right: -134px; | |
4645 | +} | |
4599 | 4646 | .box-2 .menu-submenu, .box-3 .menu-submenu { |
4600 | 4647 | bottom: 78px; |
4601 | 4648 | right: -44px; |
... | ... | @@ -4630,7 +4677,7 @@ h1#agenda-title { |
4630 | 4677 | .msie7 #search-results .menu-submenu-trigger { |
4631 | 4678 | width: 20px !important; |
4632 | 4679 | } |
4633 | -.common-profile-list-block .vcard .menu-submenu a { | |
4680 | +.common-profile-list-block .vcard .menu-submenu a, .comment-actions .vcard .menu-submenu a { | |
4634 | 4681 | float: none; |
4635 | 4682 | display: block; |
4636 | 4683 | height: auto; | ... | ... |
... | ... | @@ -0,0 +1,562 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | +require 'comment_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class CommentController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class CommentControllerTest < ActionController::TestCase | |
8 | + | |
9 | + def setup | |
10 | + @controller = CommentController.new | |
11 | + @request = ActionController::TestRequest.new | |
12 | + @response = ActionController::TestResponse.new | |
13 | + | |
14 | + @profile = create_user('testinguser').person | |
15 | + @environment = @profile.environment | |
16 | + end | |
17 | + attr_reader :profile, :environment | |
18 | + | |
19 | + should "not be able to remove other people's comments if not moderator or admin" do | |
20 | + create_user('normaluser') | |
21 | + profile = create_user('testuser').person | |
22 | + article = profile.articles.build(:name => 'test') | |
23 | + article.save! | |
24 | + | |
25 | + commenter = create_user('otheruser').person | |
26 | + comment = fast_create(Comment, :source_id => article, :title => 'a comment', :body => 'lalala') | |
27 | + | |
28 | + login_as 'normaluser' # normaluser cannot remove other people's comments | |
29 | + assert_no_difference Comment, :count do | |
30 | + post :destroy, :profile => profile.identifier, :id => comment.id | |
31 | + end | |
32 | + end | |
33 | + | |
34 | + should "not be able to remove other people's comments if not moderator or admin and return json if is an ajax request" do | |
35 | + create_user('normaluser') | |
36 | + profile = create_user('testuser').person | |
37 | + article = profile.articles.build(:name => 'test') | |
38 | + article.save! | |
39 | + | |
40 | + commenter = create_user('otheruser').person | |
41 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
42 | + | |
43 | + login_as 'normaluser' # normaluser cannot remove other people's comments | |
44 | + assert_no_difference Comment, :count do | |
45 | + xhr :post, :destroy, :profile => profile.identifier, :id => comment.id | |
46 | + assert_response :success | |
47 | + end | |
48 | + assert_match /\{\"ok\":false\}/, @response.body | |
49 | + end | |
50 | + | |
51 | + should 'be able to remove comments on their articles' do | |
52 | + profile = create_user('testuser').person | |
53 | + article = profile.articles.build(:name => 'test') | |
54 | + article.save! | |
55 | + | |
56 | + commenter = create_user('otheruser').person | |
57 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
58 | + | |
59 | + login_as 'testuser' # testuser must be able to remove comments in his articles | |
60 | + assert_difference Comment, :count, -1 do | |
61 | + xhr :post, :destroy, :profile => profile.identifier, :id => comment.id | |
62 | + assert_response :success | |
63 | + end | |
64 | + assert_match /\{\"ok\":true\}/, @response.body | |
65 | + end | |
66 | + | |
67 | + should 'be able to remove comments of their images' do | |
68 | + profile = create_user('testuser').person | |
69 | + | |
70 | + image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
71 | + image.save! | |
72 | + | |
73 | + commenter = create_user('otheruser').person | |
74 | + comment = fast_create(Comment, :source_id => image, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
75 | + | |
76 | + login_as 'testuser' # testuser must be able to remove comments in his articles | |
77 | + assert_difference Comment, :count, -1 do | |
78 | + xhr :post, :destroy, :profile => profile.identifier, :id => comment.id | |
79 | + assert_response :success | |
80 | + end | |
81 | + end | |
82 | + | |
83 | + should 'be able to remove comments if is moderator' do | |
84 | + commenter = create_user('commenter_user').person | |
85 | + community = Community.create!(:name => 'Community test', :identifier => 'community-test') | |
86 | + article = community.articles.create!(:name => 'test', :profile => community) | |
87 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
88 | + community.add_moderator(profile) | |
89 | + login_as profile.identifier | |
90 | + assert_difference Comment, :count, -1 do | |
91 | + xhr :post, :destroy, :profile => community.identifier, :id => comment.id | |
92 | + assert_response :success | |
93 | + end | |
94 | + assert_match /\{\"ok\":true\}/, @response.body | |
95 | + end | |
96 | + | |
97 | + should 'be able to remove comment' do | |
98 | + profile = create_user('testuser').person | |
99 | + article = profile.articles.build(:name => 'test') | |
100 | + article.save! | |
101 | + comment = fast_create(Comment, :source_id => article, :author_id => profile, :title => 'a comment', :body => 'lalala') | |
102 | + | |
103 | + login_as 'testuser' | |
104 | + assert_difference Comment, :count, -1 do | |
105 | + xhr :post, :destroy, :profile => profile.identifier, :id => comment.id | |
106 | + assert_response :success | |
107 | + end | |
108 | + end | |
109 | + | |
110 | + should 'display not found page if a user should try to make a cross comment' do | |
111 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
112 | + | |
113 | + other_person = create_user('otheruser').person | |
114 | + other_page = other_person.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
115 | + | |
116 | + assert_no_difference Comment, :count do | |
117 | + xhr :post, :create, :profile => profile.identifier, :id => other_page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' } | |
118 | + end | |
119 | + assert_match /not found/, @response.body | |
120 | + end | |
121 | + | |
122 | + should 'not be able to post comment if article do not accept it' do | |
123 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) | |
124 | + | |
125 | + assert_no_difference Comment, :count do | |
126 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' } | |
127 | + end | |
128 | + assert_match /Comment not allowed in this article/, @response.body | |
129 | + end | |
130 | + | |
131 | + should "the author's comment be the logged user" do | |
132 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
133 | + | |
134 | + login_as profile.identifier | |
135 | + | |
136 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' } | |
137 | + assert_equal profile, assigns(:comment).author | |
138 | + end | |
139 | + | |
140 | + should "the articles's comment be the article passed as parameter" do | |
141 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
142 | + | |
143 | + login_as profile.identifier | |
144 | + | |
145 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' } | |
146 | + assert_equal page, assigns(:comment).article | |
147 | + end | |
148 | + | |
149 | + should 'show comment form opened on error' do | |
150 | + login_as profile.identifier | |
151 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
152 | + xhr :post, :create, :profile => @profile.identifier, :id => page.id, :comment => { :title => '', :body => '' }, :confirm => 'true' | |
153 | + response = JSON.parse @response.body | |
154 | + assert_match /<div class=\"post_comment_box opened\"/, response["html"] | |
155 | + end | |
156 | + | |
157 | + should 'show validation error when body comment is missing' do | |
158 | + login_as @profile.identifier | |
159 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
160 | + xhr :post, :create, :profile => @profile.identifier, :id => page.id, :comment => { :title => '', :body => '' }, :confirm => 'true' | |
161 | + response = JSON.parse @response.body | |
162 | + assert_match /errorExplanation/, response["html"] | |
163 | + end | |
164 | + | |
165 | + should 'not save a comment if a plugin rejects it' do | |
166 | + class TestFilterPlugin < Noosfero::Plugin | |
167 | + def filter_comment(c) | |
168 | + c.reject! | |
169 | + end | |
170 | + end | |
171 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestFilterPlugin.new]) | |
172 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
173 | + assert_no_difference Comment, :count do | |
174 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | |
175 | + end | |
176 | + end | |
177 | + | |
178 | + should 'display a message if a plugin reject the comment' do | |
179 | + class TestFilterPlugin < Noosfero::Plugin | |
180 | + def filter_comment(c) | |
181 | + c.reject! | |
182 | + end | |
183 | + end | |
184 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestFilterPlugin.new]) | |
185 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
186 | + assert_no_difference Comment, :count do | |
187 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | |
188 | + end | |
189 | + | |
190 | + assert_match /rejected/, @response.body | |
191 | + end | |
192 | + | |
193 | + should 'store IP address, user agent and referrer for comments' do | |
194 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
195 | + @request.stubs(:remote_ip).returns('33.44.55.66') | |
196 | + @request.stubs(:referrer).returns('http://example.com') | |
197 | + @request.stubs(:user_agent).returns('MyBrowser') | |
198 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | |
199 | + comment = Comment.last | |
200 | + assert_equal '33.44.55.66', comment.ip_address | |
201 | + assert_equal 'MyBrowser', comment.user_agent | |
202 | + assert_equal 'http://example.com', comment.referrer | |
203 | + end | |
204 | + | |
205 | + should 'invalid comment display the comment form open' do | |
206 | + article = profile.articles.build(:name => 'test') | |
207 | + article.save! | |
208 | + login_as('testinguser') | |
209 | + | |
210 | + assert_no_difference Comment, :count do | |
211 | + xhr :post, :create, :profile => profile.identifier, :id =>article.id, :comment => {:body => ""}, :confirm => 'true' | |
212 | + end | |
213 | + assert_match /post_comment_box opened/, @response.body | |
214 | + end | |
215 | + | |
216 | + should 'invalid captcha display the comment form open' do | |
217 | + article = profile.articles.build(:name => 'test') | |
218 | + article.save! | |
219 | + login_as('testinguser') | |
220 | + @controller.stubs(:verify_recaptcha).returns(false) | |
221 | + | |
222 | + environment.enable('captcha_for_logged_users') | |
223 | + environment.save! | |
224 | + | |
225 | + xhr :post, :create, :profile => profile.identifier, :id =>article.id, :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
226 | + assert_match /post_comment_box opened/, @response.body | |
227 | + end | |
228 | + | |
229 | + should 'ask for captcha if environment defines even with logged user' do | |
230 | + article = profile.articles.build(:name => 'test') | |
231 | + article.save! | |
232 | + login_as('testinguser') | |
233 | + @controller.stubs(:verify_recaptcha).returns(false) | |
234 | + | |
235 | + assert_difference Comment, :count, 1 do | |
236 | + xhr :post, :create, :profile => profile.identifier, :id => article.id, :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
237 | + end | |
238 | + | |
239 | + environment.enable('captcha_for_logged_users') | |
240 | + environment.save! | |
241 | + | |
242 | + assert_no_difference Comment, :count do | |
243 | + xhr :post, :create, :profile => profile.identifier, :id =>article.id, :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
244 | + end | |
245 | + assert_not_nil assigns(:comment) | |
246 | + end | |
247 | + | |
248 | + should 'ask for captcha if user not logged' do | |
249 | + article = profile.articles.build(:name => 'test') | |
250 | + article.save! | |
251 | + | |
252 | + @controller.stubs(:verify_recaptcha).returns(false) | |
253 | + assert_no_difference Comment, :count do | |
254 | + xhr :post, :create, :profile => profile.identifier, :id => article.id, :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
255 | + end | |
256 | + | |
257 | + @controller.stubs(:verify_recaptcha).returns(true) | |
258 | + assert_difference Comment, :count, 1 do | |
259 | + xhr :post, :create, :profile => profile.identifier, :id => article.id, :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
260 | + end | |
261 | + end | |
262 | + | |
263 | + should 'create ApproveComment task when adding a comment in a moderated article' do | |
264 | + login_as @profile.identifier | |
265 | + community = Community.create!(:name => 'testcomm') | |
266 | + page = community.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
267 | + | |
268 | + commenter = create_user('otheruser').person | |
269 | + assert_difference ApproveComment, :count, 1 do | |
270 | + xhr :post, :create, :profile => community.identifier, :id => page.id, :comment => {:body => 'Some comment...', :author => commenter}, :confirm => 'true' | |
271 | + end | |
272 | + end | |
273 | + | |
274 | + should 'not create ApproveComment task when the comment author is the same of article author' do | |
275 | + login_as @profile.identifier | |
276 | + community = Community.create!(:name => 'testcomm') | |
277 | + page = community.articles.create!(:name => 'myarticle', :moderate_comments => true, :last_changed_by => @profile) | |
278 | + community.add_moderator(@profile) | |
279 | + | |
280 | + assert_no_difference ApproveComment, :count do | |
281 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...'}, :confirm => 'true' | |
282 | + end | |
283 | + end | |
284 | + | |
285 | + should 'create ApproveComment task with the comment author as requestor' do | |
286 | + community = Community.create!(:name => 'testcomm') | |
287 | + page = community.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
288 | + | |
289 | + commenter = create_user('otheruser').person | |
290 | + assert_difference ApproveComment, :count, 1 do | |
291 | + xhr :post, :create, :profile => community.identifier, :id => page.id, :comment => {:body => 'Some comment...', :author => commenter}, :confirm => 'true' | |
292 | + end | |
293 | + task = Task.last | |
294 | + assert_equal commenter, task.requestor | |
295 | + | |
296 | + end | |
297 | + | |
298 | + should "create ApproveComment task with the articles's owner profile as the target" do | |
299 | + login_as @profile.identifier | |
300 | + community = Community.create!(:name => 'testcomm') | |
301 | + page = community.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
302 | + | |
303 | + commenter = create_user('otheruser').person | |
304 | + assert_difference ApproveComment, :count, 1 do | |
305 | + xhr :post, :create, :profile => community.identifier, :id => page.id, :comment => {:body => 'Some comment...', :author => commenter}, :confirm => 'true' | |
306 | + end | |
307 | + task = Task.last | |
308 | + assert_equal community, task.target | |
309 | + end | |
310 | + | |
311 | + should "create ApproveComment task with the comment created_at attribute defined to now" do | |
312 | + login_as @profile.identifier | |
313 | + community = Community.create!(:name => 'testcomm') | |
314 | + page = community.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
315 | + | |
316 | + now = Time.now | |
317 | + Time.stubs(:now).returns(now) | |
318 | + xhr :post, :create, :profile => community.identifier, :id => page.id, :comment => {:body => 'Some comment...'}, :confirm => 'true' | |
319 | + task = Task.last | |
320 | + assert_equal now.to_s, task.comment.created_at.to_s | |
321 | + end | |
322 | + | |
323 | + should "render_target be nil in article with moderation" do | |
324 | + page = profile.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
325 | + | |
326 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...', :name => 'some name', :email => 'some@test.com.br'}, :confirm => 'true' | |
327 | + assert_nil ActiveSupport::JSON.decode(@response.body)['render_target'] | |
328 | + end | |
329 | + | |
330 | + should "display message 'waitting for approval' of comments in article with moderation" do | |
331 | + page = profile.articles.create!(:name => 'myarticle', :moderate_comments => true) | |
332 | + | |
333 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...', :name => 'some name', :email => 'some@test.com.br'}, :confirm => 'true' | |
334 | + assert_match /waiting for approval/, @response.body | |
335 | + end | |
336 | + | |
337 | + should "render_target be the comment anchor if everithing is fine" do | |
338 | + login_as profile.identifier | |
339 | + page = profile.articles.create!(:name => 'myarticle') | |
340 | + | |
341 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...'}, :confirm => 'true' | |
342 | + assert_match /#{Comment.last.id}/, ActiveSupport::JSON.decode(@response.body)['render_target'] | |
343 | + end | |
344 | + | |
345 | + should "display message 'successfully created' if the comment was saved with success" do | |
346 | + login_as profile.identifier | |
347 | + page = profile.articles.create!(:name => 'myarticle') | |
348 | + | |
349 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...'}, :confirm => 'true' | |
350 | + assert_match /successfully created/, @response.body | |
351 | + end | |
352 | + | |
353 | + should "render partial comment if everithing is fine" do | |
354 | + login_as profile.identifier | |
355 | + page = profile.articles.create!(:name => 'myarticle') | |
356 | + | |
357 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...'}, :confirm => 'true' | |
358 | + assert_match /id="#{Comment.last.anchor}" class="article-comment"/, ActiveSupport::JSON.decode(@response.body)['html'] | |
359 | + end | |
360 | + | |
361 | + should "render the root comment when a reply is made" do | |
362 | + login_as profile.identifier | |
363 | + page = profile.articles.create!(:name => 'myarticle') | |
364 | + | |
365 | + comment = fast_create(Comment, :body => 'some content', :source_id => page.id, :source_type => 'Article') | |
366 | + | |
367 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:body => 'Some comment...', :reply_of_id => comment.id}, :confirm => 'true' | |
368 | + assert_match /id="#{comment.anchor}" class="article-comment"/, ActiveSupport::JSON.decode(@response.body)['html'] | |
369 | + end | |
370 | + | |
371 | + should 'filter html content from body' do | |
372 | + login_as @profile.identifier | |
373 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
374 | + | |
375 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'html comment', :body => "this is a <strong id='html_test_comment'>html comment</strong>"} | |
376 | + | |
377 | + assert Comment.last.body.match(/this is a html comment/) | |
378 | + assert_no_tag :tag => 'strong', :attributes => { :id => 'html_test_comment' } | |
379 | + end | |
380 | + | |
381 | + should 'filter html content from title' do | |
382 | + login_as @profile.identifier | |
383 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
384 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => "html <strong id='html_test_comment'>comment</strong>", :body => "this is a comment"} | |
385 | + assert Comment.last.title.match(/html comment/) | |
386 | + assert_no_tag :tag => 'strong', :attributes => { :id => 'html_test_comment' } | |
387 | + end | |
388 | + | |
389 | + should 'touch article after adding a comment' do | |
390 | + yesterday = Time.now.yesterday | |
391 | + Article.record_timestamps = false | |
392 | + page = profile.articles.create(:name => 'myarticle', :body => 'the body of the text', :created_at => yesterday, :updated_at => yesterday) | |
393 | + Article.record_timestamps = true | |
394 | + | |
395 | + login_as('ze') | |
396 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' }, :confirm => 'true' | |
397 | + assert_not_equal yesterday, page.reload.updated_at | |
398 | + end | |
399 | + | |
400 | + should 'be able to mark comments as spam' do | |
401 | + login_as profile.identifier | |
402 | + article = fast_create(Article, :profile_id => profile.id) | |
403 | + spam = fast_create(Comment, :name => 'foo', :email => 'foo@example.com', :source_id => article.id, :source_type => 'Article') | |
404 | + | |
405 | + xhr :post, :mark_as_spam, :profile => profile.identifier, :id => spam.id | |
406 | + | |
407 | + spam.reload | |
408 | + assert spam.spam? | |
409 | + end | |
410 | + | |
411 | + should "not be able to mark as spam other people's comments if not moderator or admin" do | |
412 | + create_user('normaluser') | |
413 | + profile = create_user('testuser').person | |
414 | + article = profile.articles.build(:name => 'test') | |
415 | + article.save! | |
416 | + | |
417 | + commenter = create_user('otheruser').person | |
418 | + comment = fast_create(Comment, :source_id => article, :title => 'a comment', :body => 'lalala') | |
419 | + | |
420 | + login_as 'normaluser' # normaluser cannot remove other people's comments | |
421 | + xhr :post, :mark_as_spam, :profile => profile.identifier, :id => comment.id | |
422 | + comment.reload | |
423 | + assert !comment.spam? | |
424 | + end | |
425 | + | |
426 | + should "not be able to mark as spam other people's comments if not moderator or admin and return json if is an ajax request" do | |
427 | + create_user('normaluser') | |
428 | + profile = create_user('testuser').person | |
429 | + article = profile.articles.build(:name => 'test') | |
430 | + article.save! | |
431 | + | |
432 | + commenter = create_user('otheruser').person | |
433 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
434 | + | |
435 | + login_as 'normaluser' # normaluser cannot remove other people's comments | |
436 | + | |
437 | + xhr :post, :mark_as_spam, :profile => profile.identifier, :id => comment.id | |
438 | + assert_response :success | |
439 | + comment.reload | |
440 | + assert !comment.spam? | |
441 | + assert_match /\{\"ok\":false\}/, @response.body | |
442 | + end | |
443 | + | |
444 | + should 'be able to mark as spam comments on their articles' do | |
445 | + profile = create_user('testuser').person | |
446 | + article = profile.articles.build(:name => 'test') | |
447 | + article.save! | |
448 | + | |
449 | + commenter = create_user('otheruser').person | |
450 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
451 | + | |
452 | + login_as 'testuser' # testuser must be able to remove comments in his articles | |
453 | + | |
454 | + xhr :post, :mark_as_spam, :profile => profile.identifier, :id => comment.id | |
455 | + assert_response :success | |
456 | + comment.reload | |
457 | + assert comment.spam? | |
458 | + | |
459 | + assert_match /\{\"ok\":true\}/, @response.body | |
460 | + end | |
461 | + | |
462 | + should 'be able to mark comments as spam if is moderator' do | |
463 | + commenter = create_user('commenter_user').person | |
464 | + community = Community.create!(:name => 'Community test', :identifier => 'community-test') | |
465 | + article = community.articles.create!(:name => 'test', :profile => community) | |
466 | + comment = fast_create(Comment, :source_id => article, :author_id => commenter, :title => 'a comment', :body => 'lalala') | |
467 | + community.add_moderator(profile) | |
468 | + login_as profile.identifier | |
469 | + | |
470 | + xhr :post, :mark_as_spam, :profile => community.identifier, :id => comment.id | |
471 | + assert_response :success | |
472 | + comment.reload | |
473 | + assert comment.spam? | |
474 | + assert_match /\{\"ok\":true\}/, @response.body | |
475 | + end | |
476 | + | |
477 | + should 'edit comment from a page' do | |
478 | + login_as profile.identifier | |
479 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
480 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile.id) | |
481 | + | |
482 | + get :edit, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
483 | + assert_tag :tag => 'textarea', :attributes => {:id => 'comment_body'}, :content => 'Original comment' | |
484 | + end | |
485 | + | |
486 | + should 'not crash on edit comment if comment does not exist' do | |
487 | + login_as profile.identifier | |
488 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
489 | + | |
490 | + get :edit, :id => 1000, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
491 | + assert_response 404 | |
492 | + end | |
493 | + | |
494 | + should 'not be able to edit comment not logged' do | |
495 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
496 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article') | |
497 | + | |
498 | + get :edit, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
499 | + assert_response 404 | |
500 | + end | |
501 | + | |
502 | + should 'not be able to edit comment if does not have the permission to' do | |
503 | + user = create_user('any_guy').person | |
504 | + login_as user.identifier | |
505 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
506 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article') | |
507 | + | |
508 | + get :edit, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
509 | + assert_response 404 | |
510 | + end | |
511 | + | |
512 | + should 'be able to update a comment' do | |
513 | + login_as profile.identifier | |
514 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) | |
515 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article', :author_id => profile) | |
516 | + | |
517 | + xhr :post, :update, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
518 | + assert JSON.parse(@response.body)["ok"], "attribute ok expected to be true" | |
519 | + assert_equal 'Comment edited', Comment.find(comment.id).body | |
520 | + end | |
521 | + | |
522 | + should 'not crash on update comment if comment does not exist' do | |
523 | + login_as profile.identifier | |
524 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
525 | + | |
526 | + xhr :post, :update, :id => 1000, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
527 | + assert_response 404 | |
528 | + end | |
529 | + | |
530 | + should 'not be able to update comment not logged' do | |
531 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
532 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article') | |
533 | + | |
534 | + xhr :post, :update, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
535 | + assert_response 404 | |
536 | + end | |
537 | + | |
538 | + should 'not be able to update comment if does not have the permission to' do | |
539 | + user = create_user('any_guy').person | |
540 | + login_as user.identifier | |
541 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
542 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article') | |
543 | + | |
544 | + xhr :post, :update, :id => comment.id, :profile => profile.identifier, :comment => { :body => 'Comment edited' } | |
545 | + assert_response 404 | |
546 | + end | |
547 | + | |
548 | + should 'returns ids of menu items that has to be displayed' do | |
549 | + class TestActionPlugin < Noosfero::Plugin | |
550 | + def check_comment_actions(c) | |
551 | + ['action1', 'action2'] | |
552 | + end | |
553 | + end | |
554 | + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestActionPlugin.new]) | |
555 | + login_as profile.identifier | |
556 | + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
557 | + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article') | |
558 | + xhr :post, :check_actions, :profile => profile.identifier, :id => comment.id | |
559 | + assert_match /\{\"ids\":\[\"action1\",\"action2\"\]\}/, @response.body | |
560 | + end | |
561 | + | |
562 | +end | ... | ... |
test/functional/content_viewer_controller_test.rb
... | ... | @@ -83,149 +83,6 @@ class ContentViewerControllerTest < ActionController::TestCase |
83 | 83 | assert_equal feed.data, @response.body |
84 | 84 | end |
85 | 85 | |
86 | - should 'display remove comment button' do | |
87 | - profile = create_user('testuser').person | |
88 | - article = profile.articles.build(:name => 'test') | |
89 | - article.save! | |
90 | - comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') | |
91 | - comment.save! | |
92 | - | |
93 | - login_as 'testuser' | |
94 | - get :view_page, :profile => 'testuser', :page => [ 'test' ] | |
95 | - assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/test\?remove_comment=#{comment.id}.quot) } | |
96 | - end | |
97 | - | |
98 | - should 'display remove comment button with param view when image' do | |
99 | - profile = create_user('testuser').person | |
100 | - | |
101 | - image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
102 | - image.save! | |
103 | - | |
104 | - comment = image.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') | |
105 | - comment.save! | |
106 | - | |
107 | - login_as 'testuser' | |
108 | - get :view_page, :profile => 'testuser', :page => [ image.filename ], :view => true | |
109 | - assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/#{image.filename}\?remove_comment=#{comment.id}.*amp;view=true.quot) } | |
110 | -end | |
111 | - | |
112 | - | |
113 | - should 'not add unneeded params for remove comment button' do | |
114 | - profile = create_user('testuser').person | |
115 | - article = profile.articles.build(:name => 'test') | |
116 | - article.save! | |
117 | - comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') | |
118 | - comment.save! | |
119 | - | |
120 | - login_as 'testuser' | |
121 | - get :view_page, :profile => 'testuser', :page => [ 'test' ], :random_param => 'bli' | |
122 | - assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/test\?remove_comment=#{comment.id.to_s}.quot) } | |
123 | - end | |
124 | - | |
125 | - should 'be able to remove comment' do | |
126 | - profile = create_user('testuser').person | |
127 | - article = profile.articles.build(:name => 'test') | |
128 | - article.save! | |
129 | - comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') | |
130 | - comment.save! | |
131 | - | |
132 | - login_as 'testuser' | |
133 | - assert_difference Comment, :count, -1 do | |
134 | - post :view_page, :profile => profile.identifier, :page => [ 'test' ], :remove_comment => comment.id | |
135 | - assert_redirected_to :controller => 'content_viewer', :profile => 'testuser', :action => 'view_page', :page => [ 'test' ] | |
136 | - end | |
137 | - end | |
138 | - | |
139 | - should "not be able to remove other people's comments if not moderator or admin" do | |
140 | - create_user('normaluser') | |
141 | - profile = create_user('testuser').person | |
142 | - article = profile.articles.build(:name => 'test') | |
143 | - article.save! | |
144 | - | |
145 | - commenter = create_user('otheruser').person | |
146 | - comment = article.comments.build(:author => commenter, :title => 'a comment', :body => 'lalala') | |
147 | - comment.save! | |
148 | - | |
149 | - login_as 'normaluser' # normaluser cannot remove other people's comments | |
150 | - assert_no_difference Comment, :count do | |
151 | - post :view_page, :profile => profile.identifier, :page => [ 'test' ], :remove_comment => comment.id | |
152 | - assert_response :redirect | |
153 | - end | |
154 | - end | |
155 | - | |
156 | - should 'be able to remove comments on their articles' do | |
157 | - profile = create_user('testuser').person | |
158 | - article = profile.articles.build(:name => 'test') | |
159 | - article.save! | |
160 | - | |
161 | - commenter = create_user('otheruser').person | |
162 | - comment = article.comments.build(:author => commenter, :title => 'a comment', :body => 'lalala') | |
163 | - comment.save! | |
164 | - | |
165 | - login_as 'testuser' # testuser must be able to remove comments in his articles | |
166 | - assert_difference Comment, :count, -1 do | |
167 | - post :view_page, :profile => profile.identifier, :page => [ 'test' ], :remove_comment => comment.id | |
168 | - assert_response :redirect | |
169 | - end | |
170 | - end | |
171 | - | |
172 | - should 'be able to remove comments of their images' do | |
173 | - profile = create_user('testuser').person | |
174 | - | |
175 | - image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
176 | - image.save! | |
177 | - | |
178 | - commenter = create_user('otheruser').person | |
179 | - comment = image.comments.build(:author => commenter, :title => 'a comment', :body => 'lalala') | |
180 | - comment.save! | |
181 | - | |
182 | - login_as 'testuser' # testuser must be able to remove comments in his articles | |
183 | - assert_difference Comment, :count, -1 do | |
184 | - post :view_page, :profile => profile.identifier, :page => [ image.filename ], :remove_comment => comment.id, :view => true | |
185 | - | |
186 | - assert_response :redirect | |
187 | - assert_redirected_to :controller => 'content_viewer', :action => 'view_page', :profile => profile.identifier, :page => image.explode_path, :view => true | |
188 | - end | |
189 | - end | |
190 | - | |
191 | - should 'be able to remove comments if is moderator' do | |
192 | - commenter = create_user('commenter_user').person | |
193 | - community = Community.create!(:name => 'Community test', :identifier => 'community-test') | |
194 | - article = community.articles.create!(:name => 'test') | |
195 | - comment = article.comments.create!(:author => commenter, :title => 'a comment', :body => 'lalala') | |
196 | - community.add_moderator(profile) | |
197 | - login_as profile.identifier | |
198 | - assert_difference Comment, :count, -1 do | |
199 | - post :view_page, :profile => community.identifier, :page => [ 'test' ], :remove_comment => comment.id | |
200 | - assert_response :redirect | |
201 | - end | |
202 | - end | |
203 | - | |
204 | - should 'filter html content from body' do | |
205 | - login_as @profile.identifier | |
206 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
207 | - post :view_page, :profile => @profile.identifier, :page => [ 'myarticle' ], | |
208 | - :comment => { :title => 'html comment', :body => "this is a <strong id='html_test_comment'>html comment</strong>" } | |
209 | - assert_no_tag :tag => 'strong', :attributes => { :id => 'html_test_comment' } | |
210 | - end | |
211 | - | |
212 | - should 'filter html content from title' do | |
213 | - login_as @profile.identifier | |
214 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
215 | - post :view_page, :profile => @profile.identifier, :page => [ 'myarticle' ], | |
216 | - :comment => { :title => "html <strong id='html_test_comment'>comment</strong>", :body => "this is a comment" } | |
217 | - assert_no_tag :tag => 'strong', :attributes => { :id => 'html_test_comment' } | |
218 | - end | |
219 | - | |
220 | - should "point to article's url in comment form" do | |
221 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
222 | - Article.any_instance.stubs(:url).returns({:host => 'www.mysite.com', :controller => 'content_viewer', :action => 'view_page', :profile => 'person', :page => ['article']}) | |
223 | - | |
224 | - get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | |
225 | - | |
226 | - assert_tag :tag => 'form', :attributes => { :class => /^comment_form/, :action => '/person/article' } | |
227 | - end | |
228 | - | |
229 | 86 | should "display current article's tags" do |
230 | 87 | page = profile.articles.create!(:name => 'myarticle', :body => 'test article', :tag_list => 'tag1, tag2') |
231 | 88 | |
... | ... | @@ -429,14 +286,6 @@ end |
429 | 286 | assert_template 'view_page' |
430 | 287 | end |
431 | 288 | |
432 | - should 'not be able to post comment if article do not accept it' do | |
433 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) | |
434 | - | |
435 | - assert_no_difference Comment, :count do | |
436 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'crap!', :body => 'I think that this article is crap', :name => 'Anonymous coward', :email => 'coward@anonymous.com' } | |
437 | - end | |
438 | - end | |
439 | - | |
440 | 289 | should 'list comments if article has them, even if new comments are not allowed' do |
441 | 290 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) |
442 | 291 | page.comments.create!(:author => profile, :title => 'list my comment', :body => 'foo bar baz') |
... | ... | @@ -719,15 +568,6 @@ end |
719 | 568 | assert_tag :tag => 'a', :content => 'Upload files', :attributes => {:href => /parent_id=#{folder.id}/} |
720 | 569 | end |
721 | 570 | |
722 | - should 'post comment in a image' do | |
723 | - login_as(profile.identifier) | |
724 | - image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
725 | - comment_count = image.comments.count | |
726 | - post :view_page, :profile => profile.identifier, :page => image.explode_path, :view => true | |
727 | - assert_equal comment_count, image.reload.comments.count | |
728 | - assert_template 'view_page' | |
729 | - end | |
730 | - | |
731 | 571 | should 'render slideshow template' do |
732 | 572 | f = Folder.create!(:name => 'gallery', :profile => profile) |
733 | 573 | get :view_page, :profile => profile.identifier, :page => f.explode_path, :slideshow => true |
... | ... | @@ -869,17 +709,6 @@ end |
869 | 709 | assert_tag :tag => 'a', :content => 'New article' |
870 | 710 | end |
871 | 711 | |
872 | - should 'touch article after adding a comment' do | |
873 | - yesterday = Time.now.yesterday | |
874 | - Article.record_timestamps = false | |
875 | - page = profile.articles.create(:name => 'myarticle', :body => 'the body of the text', :created_at => yesterday, :updated_at => yesterday) | |
876 | - Article.record_timestamps = true | |
877 | - | |
878 | - login_as('ze') | |
879 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'crap!', :body => 'I think that this article is crap' } | |
880 | - assert_not_equal yesterday, assigns(:page).updated_at | |
881 | - end | |
882 | - | |
883 | 712 | should 'display message if user was removed' do |
884 | 713 | article = profile.articles.create(:name => 'comment test') |
885 | 714 | to_be_removed = create_user('removed_user').person |
... | ... | @@ -891,13 +720,6 @@ end |
891 | 720 | assert_tag :tag => 'span', :content => '(removed user)', :attributes => {:class => 'comment-user-status icon-user-removed'} |
892 | 721 | end |
893 | 722 | |
894 | - should 'show comment form opened on error' do | |
895 | - login_as @profile.identifier | |
896 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
897 | - post :view_page, :profile => @profile.identifier, :page => [ 'myarticle' ], :comment => { :title => '', :body => '' }, :confirm => 'true' | |
898 | - assert_tag :tag => 'div', :attributes => { :class => 'post_comment_box opened' } | |
899 | - end | |
900 | - | |
901 | 723 | should 'show only first paragraph of blog posts if visualization_format is short' do |
902 | 724 | login_as(profile.identifier) |
903 | 725 | |
... | ... | @@ -1188,22 +1010,14 @@ end |
1188 | 1010 | assert_equal [es_article], assigns(:posts) |
1189 | 1011 | end |
1190 | 1012 | |
1191 | - should 'be redirect after posting a comment' do | |
1192 | - login_as @profile.identifier | |
1193 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1194 | - post :view_page, :profile => @profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body' }, :confirm => 'true' | |
1195 | - assert_redirected_to :controller => 'content_viewer', :action => 'view_page', :profile => @profile.identifier, :page => page.explode_path | |
1196 | - end | |
1197 | - | |
1198 | 1013 | should 'display reply to comment button if authenticated' do |
1199 | 1014 | profile = create_user('testuser').person |
1200 | 1015 | article = profile.articles.build(:name => 'test') |
1201 | 1016 | article.save! |
1202 | - comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') | |
1203 | - comment.save! | |
1017 | + comment = Comment.create!(:author => profile, :title => 'a comment', :body => 'lalala', :article => article) | |
1204 | 1018 | login_as 'testuser' |
1205 | 1019 | get :view_page, :profile => 'testuser', :page => [ 'test' ] |
1206 | - assert_tag :tag => 'a', :attributes => { :class => /comment-footer-link/ }, :content => 'Reply' | |
1020 | + assert_tag :tag => 'a', :attributes => { :class => /comment-actions-reply/ } | |
1207 | 1021 | end |
1208 | 1022 | |
1209 | 1023 | should 'display reply to comment button if not authenticated' do |
... | ... | @@ -1213,7 +1027,7 @@ end |
1213 | 1027 | comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') |
1214 | 1028 | comment.save! |
1215 | 1029 | get :view_page, :profile => 'testuser', :page => [ 'test' ] |
1216 | - assert_tag :tag => 'a', :attributes => { :class => /comment-footer-link/ }, :content => 'Reply' | |
1030 | + assert_tag :tag => 'a', :attributes => { :class => /comment-actions-reply/ } | |
1217 | 1031 | end |
1218 | 1032 | |
1219 | 1033 | should 'display replies if comment has replies' do |
... | ... | @@ -1238,34 +1052,6 @@ end |
1238 | 1052 | assert_no_tag :tag => 'ul', :attributes => { :class => 'comment-replies' } |
1239 | 1053 | end |
1240 | 1054 | |
1241 | - should 'show reply error' do | |
1242 | - profile = create_user('testuser').person | |
1243 | - article = profile.articles.build(:name => 'test') | |
1244 | - article.save! | |
1245 | - comment = article.comments.build(:author => profile, :title => 'root', :body => 'root') | |
1246 | - comment.save! | |
1247 | - login_as 'testuser' | |
1248 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => { :title => '', :body => '', :reply_of_id => comment.id }, :confirm => 'true' | |
1249 | - assert_tag :tag => 'div', :attributes => { :class => /comment_reply/ }, :descendant => {:tag => 'div', :attributes => {:class => 'errorExplanation'} } | |
1250 | - assert_no_tag :tag => 'div', :attributes => { :id => 'page-comment-form' }, :descendant => {:tag => 'div', :attributes => {:class => 'errorExplanation'} } | |
1251 | - assert_tag :tag => 'div', :attributes => { :id => 'page-comment-form' }, :descendant => { :tag => 'div', :attributes => { :class => /post_comment_box closed/ } } | |
1252 | - end | |
1253 | - | |
1254 | - should 'show comment error' do | |
1255 | - profile = create_user('testuser').person | |
1256 | - article = profile.articles.build(:name => 'test') | |
1257 | - article.save! | |
1258 | - comment1 = article.comments.build(:author => profile, :title => 'root', :body => 'root') | |
1259 | - comment1.save! | |
1260 | - comment2 = article.comments.build(:author => profile, :title => 'root', :body => 'root', :reply_of_id => comment1.id) | |
1261 | - comment2.save! | |
1262 | - login_as 'testuser' | |
1263 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => { :title => '', :body => '' }, :confirm => 'true' | |
1264 | - assert_no_tag :tag => 'div', :attributes => { :class => /comment_reply/ }, :descendant => {:tag => 'div', :attributes => {:class => 'errorExplanation'} } | |
1265 | - assert_tag :tag => 'div', :attributes => { :id => 'page-comment-form' }, :descendant => {:tag => 'div', :attributes => {:class => 'errorExplanation'} } | |
1266 | - assert_tag :tag => 'div', :attributes => { :id => 'page-comment-form' }, :descendant => { :tag => 'div', :attributes => { :class => /post_comment_box opened/ } } | |
1267 | - end | |
1268 | - | |
1269 | 1055 | should 'add an zero width space every 4 caracters of comment urls' do |
1270 | 1056 | url = 'www.an.url.to.be.splited.com' |
1271 | 1057 | a = fast_create(TextileArticle, :profile_id => @profile.id, :path => 'textile', :language => 'en') |
... | ... | @@ -1346,60 +1132,6 @@ end |
1346 | 1132 | assert_no_tag :tag => 'body', :attributes => { :class => /profile-homepage/ } |
1347 | 1133 | end |
1348 | 1134 | |
1349 | - should 'ask for captcha if user not logged' do | |
1350 | - article = profile.articles.build(:name => 'test') | |
1351 | - article.save! | |
1352 | - | |
1353 | - @controller.stubs(:verify_recaptcha).returns(false) | |
1354 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
1355 | - assert_not_nil assigns(:comment) | |
1356 | - | |
1357 | - @controller.stubs(:verify_recaptcha).returns(true) | |
1358 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
1359 | - assert_nil assigns(:comment) | |
1360 | - end | |
1361 | - | |
1362 | - should 'ask for captcha if environment defines even with logged user' do | |
1363 | - article = profile.articles.build(:name => 'test') | |
1364 | - article.save! | |
1365 | - login_as('testinguser') | |
1366 | - @controller.stubs(:verify_recaptcha).returns(false) | |
1367 | - | |
1368 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
1369 | - assert_nil assigns(:comment) | |
1370 | - | |
1371 | - environment.enable('captcha_for_logged_users') | |
1372 | - environment.save! | |
1373 | - | |
1374 | - post :view_page, :profile => profile.identifier, :page => ['test'], :comment => {:body => "Some comment...", :author => profile}, :confirm => 'true' | |
1375 | - assert_not_nil assigns(:comment) | |
1376 | - end | |
1377 | - | |
1378 | - should 'store IP address, user agent and referrer for comments' do | |
1379 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1380 | - @request.stubs(:remote_ip).returns('33.44.55.66') | |
1381 | - @request.stubs(:referrer).returns('http://example.com') | |
1382 | - @request.stubs(:user_agent).returns('MyBrowser') | |
1383 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | |
1384 | - comment = Comment.last | |
1385 | - assert_equal '33.44.55.66', comment.ip_address | |
1386 | - assert_equal 'MyBrowser', comment.user_agent | |
1387 | - assert_equal 'http://example.com', comment.referrer | |
1388 | - end | |
1389 | - | |
1390 | - should 'not save a comment if a plugin rejects it' do | |
1391 | - class TestFilterPlugin < Noosfero::Plugin | |
1392 | - def filter_comment(c) | |
1393 | - c.reject! | |
1394 | - end | |
1395 | - end | |
1396 | - Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestFilterPlugin.new]) | |
1397 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1398 | - assert_no_difference Comment, :count do | |
1399 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | |
1400 | - end | |
1401 | - end | |
1402 | - | |
1403 | 1135 | should 'not display article actions button if any plugins says so' do |
1404 | 1136 | class Plugin1 < Noosfero::Plugin |
1405 | 1137 | def content_remove_edit(content); true; end |
... | ... | @@ -1453,53 +1185,4 @@ end |
1453 | 1185 | assert_equal 1, assigns(:comments_count) |
1454 | 1186 | end |
1455 | 1187 | |
1456 | - should 'be able to mark comments as spam' do | |
1457 | - login_as profile.identifier | |
1458 | - article = fast_create(Article, :profile_id => profile.id) | |
1459 | - spam = fast_create(Comment, :name => 'foo', :email => 'foo@example.com', :source_id => article.id, :source_type => 'Article') | |
1460 | - | |
1461 | - post 'view_page', :profile => profile.identifier, :page => article.path.split('/'), :mark_comment_as_spam => spam.id | |
1462 | - | |
1463 | - spam.reload | |
1464 | - assert spam.spam? | |
1465 | - end | |
1466 | - | |
1467 | - should 'be able to edit a comment' do | |
1468 | - login_as profile.identifier | |
1469 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text', :accept_comments => false) | |
1470 | - comment = fast_create(Comment, :body => 'Original comment', :author_id => profile.id, :source_id => page.id, :source_type => 'Article') | |
1471 | - | |
1472 | - post :edit_comment, :id => comment.id, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :body => 'Comment edited' } | |
1473 | - assert_equal 'Comment edited', Comment.find(comment.id).body | |
1474 | - end | |
1475 | - | |
1476 | - should 'edit comment from a page' do | |
1477 | - login_as profile.identifier | |
1478 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1479 | - comment = fast_create(Comment, :body => 'Original comment', :author_id => profile.id, :source_id => page.id, :source_type => 'Article') | |
1480 | - | |
1481 | - get :edit_comment, :id => comment.id, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :body => 'Comment edited' } | |
1482 | - assert_tag :tag => 'h1', :content => 'Edit comment' | |
1483 | - end | |
1484 | - | |
1485 | - should 'not edit comment from other page' do | |
1486 | - login_as profile.identifier | |
1487 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1488 | - comment = fast_create(Comment, :body => 'Original comment', :author_id => profile.id, :source_id => page.id, :source_type => 'Article') | |
1489 | - | |
1490 | - other_page = profile.articles.create!(:name => 'my other article', :body => 'the body of the text') | |
1491 | - comment_on_other_page = fast_create(Comment, :body => 'Comment on other article', :author_id => profile.id, :source_id => other_page.id, :source_type => 'Article') | |
1492 | - | |
1493 | - get :edit_comment, :id => comment_on_other_page.id, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :body => 'Comment edited' } | |
1494 | - assert_redirected_to page.url | |
1495 | - end | |
1496 | - | |
1497 | - should 'not crash on edit comment if comment does not exist' do | |
1498 | - login_as profile.identifier | |
1499 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | |
1500 | - | |
1501 | - get :edit_comment, :id => 1000, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :body => 'Comment edited' } | |
1502 | - assert_response 404 | |
1503 | - end | |
1504 | - | |
1505 | 1188 | end | ... | ... |
... | ... | @@ -0,0 +1,217 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class ApproveCommentTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + ActionMailer::Base.delivery_method = :test | |
7 | + ActionMailer::Base.perform_deliveries = true | |
8 | + ActionMailer::Base.deliveries = [] | |
9 | + @profile = create_user('test_user', :email => "someone@anyhost.com").person | |
10 | + @article = fast_create(TextileArticle, :profile_id => @profile.id, :name => 'test name', :abstract => 'Lead of article', :body => 'This is my article') | |
11 | + @community = create(Community, :contact_email => "someone@anyhost.com") | |
12 | + @comment = @article.comments.build(:title => 'any comment', :body => "any text", :author => create_user('someperson').person) | |
13 | + end | |
14 | + | |
15 | + attr_reader :profile, :article, :community | |
16 | + | |
17 | + should 'be a task' do | |
18 | + ok { ApproveComment.new.kind_of?(Task) } | |
19 | + end | |
20 | + | |
21 | + should 'comment method deserialize comment attributes' do | |
22 | + a = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
23 | + assert_equal @comment.attributes, a.comment.attributes | |
24 | + end | |
25 | + | |
26 | + should 'article method returns comment article' do | |
27 | + @comment.article = @article | |
28 | + a = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
29 | + assert_equal @article, @comment.article | |
30 | + end | |
31 | + | |
32 | + should 'article method returns nil if comment.article if nil' do | |
33 | + @comment.article = nil | |
34 | + a = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
35 | + assert_nil @comment.article | |
36 | + end | |
37 | + | |
38 | + should 'not raise in comment action if comment_attributes if nil' do | |
39 | + a = ApproveComment.new(:comment_attributes => nil) | |
40 | + assert_nothing_raised do | |
41 | + a.comment | |
42 | + end | |
43 | + end | |
44 | + | |
45 | + should 'have article_name reference comment article' do | |
46 | + approve_comment = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
47 | + | |
48 | + assert_equal @article.name, approve_comment.article_name | |
49 | + end | |
50 | + | |
51 | + should 'article_name be article removed if there is no article associated to comment' do | |
52 | + @comment.article = nil | |
53 | + approve_comment = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
54 | + | |
55 | + assert_equal "Article removed.", approve_comment.article_name | |
56 | + end | |
57 | + | |
58 | + should 'have linked_subject reference comment article' do | |
59 | + approve_comment = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
60 | + | |
61 | + expected = {:text => @article.name, :url => @article.url} | |
62 | + assert_equal expected, approve_comment.linked_subject | |
63 | + end | |
64 | + | |
65 | + should 'have linked_subject ne nil if there is no article associated to comment' do | |
66 | + @comment.article = nil | |
67 | + approve_comment = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
68 | + | |
69 | + assert_nil approve_comment.linked_subject | |
70 | + end | |
71 | + | |
72 | + should 'create comment when finishing task' do | |
73 | + approve_comment = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
74 | + assert_difference @article.comments, :count, 1 do | |
75 | + approve_comment.finish | |
76 | + end | |
77 | + end | |
78 | + | |
79 | + should 'create comment with the created_at atribute passed as parameter when finishing task' do | |
80 | + now = Time.now - 10 | |
81 | + @comment.created_at = now | |
82 | + approve_comment = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
83 | + assert_difference @article.comments, :count, 1 do | |
84 | + approve_comment.finish | |
85 | + end | |
86 | + comment = Comment.last | |
87 | + assert_equal now.to_s, comment.created_at.to_s | |
88 | + end | |
89 | + | |
90 | + should 'require target (profile which the article is going to be commented)' do | |
91 | + task = ApproveComment.new | |
92 | + task.valid? | |
93 | + | |
94 | + ok('must not validate with empty target') { task.errors.invalid?(:target_id) } | |
95 | + | |
96 | + task.target = Person.new | |
97 | + task.valid? | |
98 | + ok('must validate when target is given') { task.errors.invalid?(:target_id)} | |
99 | + end | |
100 | + | |
101 | + should 'send e-mails' do | |
102 | + TaskMailer.expects(:deliver_target_notification).at_least_once | |
103 | + | |
104 | + task = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
105 | + | |
106 | + end | |
107 | + | |
108 | + should 'override target notification message method from Task' do | |
109 | + task = ApproveComment.new(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
110 | + assert_nothing_raised NotImplementedError do | |
111 | + task.target_notification_message | |
112 | + end | |
113 | + end | |
114 | + | |
115 | + should 'deliver target notification message' do | |
116 | + task = ApproveComment.new(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
117 | + | |
118 | + email = TaskMailer.deliver_target_notification(task, task.target_notification_message) | |
119 | + assert_match(/\[#{task.environment.name}\] #{task.requestor.name} wants to comment the article: #{task.article_name}/, email.subject) | |
120 | + end | |
121 | + | |
122 | + should 'alert when reference article is removed' do | |
123 | + a = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
124 | + | |
125 | + @article.destroy | |
126 | + a.reload | |
127 | + assert_equal "The article was removed.", a.information[:message] | |
128 | + end | |
129 | + | |
130 | + should 'display anonymous name if the requestor is nil' do | |
131 | + a = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => nil) | |
132 | + | |
133 | + assert_match /nonymous/, a.information[:message] | |
134 | + end | |
135 | + | |
136 | + should 'accept_details be true' do | |
137 | + a = ApproveComment.new | |
138 | + assert a.accept_details | |
139 | + end | |
140 | + | |
141 | + should 'reject_details be true' do | |
142 | + a = ApproveComment.new | |
143 | + assert a.reject_details | |
144 | + end | |
145 | + | |
146 | + should 'default decision be skip if there is an article associated to task' do | |
147 | + a = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
148 | + assert 'skip', a.default_decision | |
149 | + end | |
150 | + | |
151 | + should 'default decision be reject if there is no article associated to task' do | |
152 | + a = ApproveComment.new() | |
153 | + assert 'reject', a.default_decision | |
154 | + end | |
155 | + | |
156 | + should 'accept_disabled be true if there is no article associated to task' do | |
157 | + a = ApproveComment.new | |
158 | + assert a.accept_disabled? | |
159 | + end | |
160 | + | |
161 | + should 'accept_disabled be false if there is an article associated to task' do | |
162 | + a = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
163 | + assert !a.accept_disabled? | |
164 | + end | |
165 | + | |
166 | + should 'have target notification description' do | |
167 | + task = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
168 | + | |
169 | + assert_match(/#{task.requestor.name} wants to comment the article: #{article.name}/, task.target_notification_description) | |
170 | + end | |
171 | + | |
172 | + should 'have an target notification description for comments on removed articles' do | |
173 | + task = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
174 | + | |
175 | + @article.destroy | |
176 | + assert_match(/#{task.requestor.name} wanted to comment the article but it was removed/, task.target_notification_description) | |
177 | + end | |
178 | + | |
179 | + should 'have a default finished messsage after approval' do | |
180 | + task = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
181 | + assert_match(/Your request for comment the article "#{task.article.title}" was approved/, task.task_finished_message) | |
182 | + end | |
183 | + | |
184 | + should 'have a personalized finished messsage after approval' do | |
185 | + task = ApproveComment.create!(:target => @community, :comment_attributes => @comment.attributes.to_json, :requestor => @profile) | |
186 | + task.stubs(:closing_statment).returns('somenthing') | |
187 | + | |
188 | + assert_match(/Your .*#{task.article.title}.*Here is the comment.*\n\n#{task.closing_statment}/, task.task_finished_message) | |
189 | + end | |
190 | + | |
191 | + should 'return reject message even without reject explanation' do | |
192 | + task = ApproveComment.new | |
193 | + assert_not_nil task.task_cancelled_message | |
194 | + end | |
195 | + | |
196 | + should 'show the name of the article in the reject message' do | |
197 | + task = ApproveComment.new(:comment_attributes => @comment.attributes.to_json) | |
198 | + assert_match /Your request for commenting the article .*#{@article.name}.* was rejected/, task.task_cancelled_message | |
199 | + end | |
200 | + | |
201 | + should 'return reject message with reject explanation' do | |
202 | + task = ApproveComment.new | |
203 | + task.reject_explanation= "Some reject explanation" | |
204 | + assert_match(/Your request for commenting .* Here is the reject explanation .*\n\n#{task.reject_explanation}/, task.task_cancelled_message) | |
205 | + end | |
206 | + | |
207 | + should 'requestor name be the name of the requestor' do | |
208 | + a = fast_create(ApproveComment, :target_id => community, :requestor_id => profile) | |
209 | + assert_equal profile.name, a.requestor_name | |
210 | + end | |
211 | + | |
212 | + should 'requestor name be Anonymous if there is no requestor' do | |
213 | + a = fast_create(ApproveComment, :target_id => community) | |
214 | + assert_equal 'Anonymous', a.requestor_name | |
215 | + end | |
216 | + | |
217 | +end | ... | ... |
test/unit/article_test.rb
... | ... | @@ -664,6 +664,30 @@ class ArticleTest < ActiveSupport::TestCase |
664 | 664 | assert a.notify_comments? |
665 | 665 | end |
666 | 666 | |
667 | + should 'has moderate comments false by default' do | |
668 | + a = Article.create!(:name => 'my article', :body => 'my text', :profile_id => profile.id) | |
669 | + a.reload | |
670 | + assert a.moderate_comments == false | |
671 | + end | |
672 | + | |
673 | + should 'save a article with moderate comments as true' do | |
674 | + a = Article.create!(:name => 'my article', :body => 'my text', :profile_id => profile.id, :moderate_comments => true) | |
675 | + a.reload | |
676 | + assert a.moderate_comments | |
677 | + end | |
678 | + | |
679 | + should 'moderate_comments? return true if moderate_comments variable is true' do | |
680 | + a = Article.new | |
681 | + a.moderate_comments= true | |
682 | + assert a.moderate_comments? | |
683 | + end | |
684 | + | |
685 | + should 'moderate_comments? return false if moderate_comments variable is false' do | |
686 | + a = Article.new | |
687 | + a.moderate_comments= false | |
688 | + assert !a.moderate_comments? | |
689 | + end | |
690 | + | |
667 | 691 | should 'hold hits count' do |
668 | 692 | a = fast_create(Article, :name => 'Test article', :profile_id => profile.id) |
669 | 693 | a.hits = 10 | ... | ... |
... | ... | @@ -0,0 +1,139 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class CommentHelperTest < ActiveSupport::TestCase | |
4 | + | |
5 | + include CommentHelper | |
6 | + include ActionView::Helpers::TagHelper | |
7 | + include NoosferoTestHelper | |
8 | + | |
9 | + def setup | |
10 | + @user = create_user('usertest').person | |
11 | + @profile = @user | |
12 | + self.stubs(:logged_in?).returns(true) | |
13 | + self.stubs(:report_abuse).returns('<a href="#">link</a>') | |
14 | + self.stubs(:expirable_comment_link).returns('<a href="#">link</a>') | |
15 | + @plugins.stubs(:dispatch).returns([]) | |
16 | + end | |
17 | + | |
18 | + attr_reader :user, :profile | |
19 | + | |
20 | + should 'show menu if it has links for actions' do | |
21 | + article = Article.new(:profile => profile) | |
22 | + comment = Comment.new(:article => article) | |
23 | + menu = comment_actions(comment) | |
24 | + assert menu | |
25 | + end | |
26 | + | |
27 | + should 'do not show menu if it has no actions' do | |
28 | + comment = Comment.new | |
29 | + self.stubs(:links_for_comment_actions).returns([]) | |
30 | + menu = comment_actions(comment) | |
31 | + assert !menu | |
32 | + end | |
33 | + | |
34 | + should 'do not show menu if it has nil actions only' do | |
35 | + comment = Comment.new | |
36 | + self.stubs(:link_for_report_abuse).returns(nil) | |
37 | + self.stubs(:link_for_spam).returns(nil) | |
38 | + self.stubs(:link_for_edit).returns(nil) | |
39 | + self.stubs(:link_for_remove).returns(nil) | |
40 | + menu = comment_actions(comment) | |
41 | + assert !menu | |
42 | + end | |
43 | + | |
44 | + should 'include actions of plugins in menu' do | |
45 | + article = Article.new(:profile => profile) | |
46 | + comment = Comment.new(:article => article) | |
47 | + plugin_action = {:link => 'plugin_action'} | |
48 | + @plugins.stubs(:dispatch).returns([plugin_action]) | |
49 | + links = links_for_comment_actions(comment) | |
50 | + assert_includes links, plugin_action | |
51 | + end | |
52 | + | |
53 | + should 'include lambda actions of plugins in menu' do | |
54 | + article = Article.new(:profile => profile) | |
55 | + comment = Comment.new(:article => article) | |
56 | + plugin_action = lambda{[{:link => 'plugin_action'}, {:link => 'plugin_action2'}]} | |
57 | + @plugins.stubs(:dispatch).returns([plugin_action]) | |
58 | + links = links_for_comment_actions(comment) | |
59 | + assert_includes links, {:link => 'plugin_action'} | |
60 | + assert_includes links, {:link => 'plugin_action2'} | |
61 | + end | |
62 | + | |
63 | + should 'return link for report abuse action when comment has a author' do | |
64 | + comment = Comment.new | |
65 | + comment.author = user | |
66 | + link = link_for_report_abuse(comment) | |
67 | + assert link | |
68 | + end | |
69 | + | |
70 | + should 'do not return link for report abuse action when comment has no author' do | |
71 | + comment = Comment.new | |
72 | + link = link_for_report_abuse(comment) | |
73 | + assert !link | |
74 | + end | |
75 | + | |
76 | + should 'return link for mark comment as spam' do | |
77 | + comment = Comment.new | |
78 | + comment.stubs(:can_be_marked_as_spam_by?).with(user).returns(true) | |
79 | + link = link_for_spam(comment) | |
80 | + assert_match /Mark as SPAM/, link[:link] | |
81 | + end | |
82 | + | |
83 | + should 'not return link for mark comment as spam if user does not have the permissions' do | |
84 | + comment = Comment.new | |
85 | + comment.stubs(:can_be_marked_as_spam_by?).with(user).returns(false) | |
86 | + link = link_for_spam(comment) | |
87 | + assert_nil link | |
88 | + end | |
89 | + | |
90 | + should 'return link for mark comment as not spam' do | |
91 | + comment = Comment.new | |
92 | + comment.spam = true | |
93 | + comment.stubs(:can_be_marked_as_spam_by?).with(user).returns(true) | |
94 | + link = link_for_spam(comment) | |
95 | + assert_match /Mark as NOT SPAM/, link[:link] | |
96 | + end | |
97 | + | |
98 | + should 'not return link for mark comment as not spam if user does not have the permissions' do | |
99 | + comment = Comment.new | |
100 | + comment.spam = true | |
101 | + comment.stubs(:can_be_marked_as_spam_by?).with(user).returns(false) | |
102 | + link = link_for_spam(comment) | |
103 | + assert_nil link | |
104 | + end | |
105 | + | |
106 | + should 'do not return link for edit comment' do | |
107 | + comment = Comment.new | |
108 | + comment.stubs(:can_be_updated_by?).with(user).returns(false) | |
109 | + link = link_for_edit(comment) | |
110 | + assert_nil link | |
111 | + end | |
112 | + | |
113 | + should 'return link for edit comment' do | |
114 | + comment = Comment.new | |
115 | + comment.stubs(:can_be_updated_by?).with(user).returns(true) | |
116 | + link = link_for_edit(comment) | |
117 | + assert link | |
118 | + end | |
119 | + | |
120 | + should 'do not return link for remove comment' do | |
121 | + comment = Comment.new | |
122 | + comment.stubs(:can_be_destroyed_by?).with(user).returns(false) | |
123 | + link = link_for_remove(comment) | |
124 | + assert_nil link | |
125 | + end | |
126 | + | |
127 | + should 'return link for remove comment' do | |
128 | + comment = Comment.new | |
129 | + comment.stubs(:can_be_destroyed_by?).with(user).returns(true) | |
130 | + link = link_for_remove(comment) | |
131 | + assert link | |
132 | + end | |
133 | + | |
134 | + def link_to_function(content, url, options = {}) | |
135 | + link_to(content, url, options) | |
136 | + end | |
137 | + | |
138 | +end | |
139 | + | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -550,6 +550,156 @@ class CommentTest < ActiveSupport::TestCase |
550 | 550 | SpammerLogger.clean_log |
551 | 551 | end |
552 | 552 | |
553 | + should 'not need moderation if article is not moderated' do | |
554 | + article = Article.new | |
555 | + comment = Comment.new(:article => article) | |
556 | + | |
557 | + assert !comment.need_moderation? | |
558 | + end | |
559 | + | |
560 | + should 'not need moderation if the comment author is the article author' do | |
561 | + author = Person.new | |
562 | + article = Article.new | |
563 | + | |
564 | + article.stubs(:author).returns(author) | |
565 | + article.moderate_comments = true | |
566 | + | |
567 | + comment = Comment.new(:article => article) | |
568 | + comment.stubs(:author).returns(author) | |
569 | + | |
570 | + assert !comment.need_moderation? | |
571 | + end | |
572 | + | |
573 | + should 'need moderation if article is moderated and the comment has no author' do | |
574 | + article = Article.new | |
575 | + article.stubs(:moderate_comments?).returns(true) | |
576 | + | |
577 | + comment = Comment.new(:article => article) | |
578 | + | |
579 | + assert comment.need_moderation? | |
580 | + end | |
581 | + | |
582 | + should 'need moderation if article is moderated and the comment author is different from article author' do | |
583 | + article_author = Person.new | |
584 | + comment_author = Person.new | |
585 | + | |
586 | + article = Article.new | |
587 | + article.stubs(:author).returns(article_author) | |
588 | + article.stubs(:moderate_comments?).returns(true) | |
589 | + | |
590 | + comment = Comment.new(:article => article) | |
591 | + comment.stubs(:author).returns(comment_author) | |
592 | + | |
593 | + assert comment.need_moderation? | |
594 | + end | |
595 | + | |
596 | + should 'not be able to destroy comment without user' do | |
597 | + comment = Comment.new | |
598 | + | |
599 | + assert !comment.can_be_destroyed_by?(nil) | |
600 | + end | |
601 | + | |
602 | + should 'not be able to destroy comment' do | |
603 | + user = Person.new | |
604 | + profile = Profile.new | |
605 | + article = Article.new(:profile => profile) | |
606 | + comment = Comment.new(:article => article) | |
607 | + user.expects(:has_permission?).with(:moderate_comments, profile).returns(false) | |
608 | + | |
609 | + assert !comment.can_be_destroyed_by?(user) | |
610 | + end | |
611 | + | |
612 | + should 'be able to destroy comment if is the author' do | |
613 | + user = Person.new | |
614 | + comment = Comment.new(:author => user) | |
615 | + | |
616 | + assert comment.can_be_destroyed_by?(user) | |
617 | + end | |
618 | + | |
619 | + should 'be able to destroy comment if is the profile' do | |
620 | + user = Person.new | |
621 | + article = Article.new(:profile => user) | |
622 | + comment = Comment.new(:article => article) | |
623 | + | |
624 | + assert comment.can_be_destroyed_by?(user) | |
625 | + end | |
626 | + | |
627 | + should 'be able to destroy comment if can moderate_comments on the profile' do | |
628 | + user = Person.new | |
629 | + profile = Profile.new | |
630 | + article = Article.new(:profile => profile) | |
631 | + comment = Comment.new(:article => article) | |
632 | + | |
633 | + user.expects(:has_permission?).with(:moderate_comments, profile).returns(true) | |
634 | + | |
635 | + assert comment.can_be_destroyed_by?(user) | |
636 | + end | |
637 | + | |
638 | + should 'not be able to mark comment as spam without user' do | |
639 | + comment = Comment.new | |
640 | + | |
641 | + assert !comment.can_be_marked_as_spam_by?(nil) | |
642 | + end | |
643 | + | |
644 | + should 'not be able to mark comment as spam' do | |
645 | + user = Person.new | |
646 | + profile = Profile.new | |
647 | + article = Article.new(:profile => profile) | |
648 | + comment = Comment.new(:article => article) | |
649 | + user.expects(:has_permission?).with(:moderate_comments, profile).returns(false) | |
650 | + | |
651 | + assert !comment.can_be_marked_as_spam_by?(user) | |
652 | + end | |
653 | + | |
654 | + should 'be able to mark comment as spam if is the profile' do | |
655 | + user = Person.new | |
656 | + article = Article.new(:profile => user) | |
657 | + comment = Comment.new(:article => article) | |
658 | + | |
659 | + assert comment.can_be_marked_as_spam_by?(user) | |
660 | + end | |
661 | + | |
662 | + should 'be able to mark comment as spam if can moderate_comments on the profile' do | |
663 | + user = Person.new | |
664 | + profile = Profile.new | |
665 | + article = Article.new(:profile => profile) | |
666 | + comment = Comment.new(:article => article) | |
667 | + | |
668 | + user.expects(:has_permission?).with(:moderate_comments, profile).returns(true) | |
669 | + | |
670 | + assert comment.can_be_marked_as_spam_by?(user) | |
671 | + end | |
672 | + | |
673 | + should 'not be able to update comment without user' do | |
674 | + comment = Comment.new | |
675 | + | |
676 | + assert !comment.can_be_updated_by?(nil) | |
677 | + end | |
678 | + | |
679 | + should 'not be able to update comment' do | |
680 | + user = Person.new | |
681 | + comment = Comment.new | |
682 | + | |
683 | + assert !comment.can_be_updated_by?(user) | |
684 | + end | |
685 | + | |
686 | + should 'be able to update comment if is the author' do | |
687 | + user = Person.new | |
688 | + comment = Comment.new(:author => user) | |
689 | + | |
690 | + assert comment.can_be_updated_by?(user) | |
691 | + end | |
692 | + | |
693 | + should 'get comment root' do | |
694 | + c1 = Comment.new | |
695 | + c2 = Comment.new(:reply_of => c1) | |
696 | + c3 = Comment.new(:reply_of => c2) | |
697 | + | |
698 | + assert_equal c1, c3.comment_root | |
699 | + assert_equal c1, c2.comment_root | |
700 | + assert_equal c1, c1.comment_root | |
701 | + end | |
702 | + | |
553 | 703 | private |
554 | 704 | |
555 | 705 | def create_comment(args = {}) | ... | ... |