Commit 44627b4a898e59f5a5082404e65bc09a19b65a88

Authored by Lucas Melo
1 parent 688b3512

use anti_spam plugin in suggest_articles

ActionItem2691
app/controllers/my_profile/cms_controller.rb
... ... @@ -267,7 +267,10 @@ class CmsController < MyProfileController
267 267 @back_to = params[:back_to] || request.referer || url_for(profile.public_profile_url)
268 268 @task = SuggestArticle.new(params[:task])
269 269 if request.post?
270   - @task.target = profile
  270 + @task.target = profile
  271 + @task.ip_address = request.remote_ip
  272 + @task.user_agent = request.user_agent
  273 + @task.referrer = request.referrer
271 274 if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save
272 275 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
273 276 redirect_to @back_to
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -4,7 +4,7 @@ class ProfileEditorController < MyProfileController
4 4 protect 'destroy_profile', :profile, :only => [:destroy_profile]
5 5  
6 6 def index
7   - @pending_tasks = Task.to(profile).pending.select{|i| user.has_permission?(i.permission, profile)}
  7 + @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)}
8 8 end
9 9  
10 10 helper :profile
... ...
app/controllers/my_profile/spam_controller.rb
... ... @@ -14,9 +14,15 @@ class SpamController < MyProfileController
14 14 if params[:remove_comment]
15 15 profile.comments_received.find(params[:remove_comment]).destroy
16 16 end
  17 + if params[:remove_task]
  18 + Task.to(profile).find_by_id(params[:remove_task]).destroy
  19 + end
17 20 if params[:mark_comment_as_ham]
18 21 profile.comments_received.find(params[:mark_comment_as_ham]).ham!
19 22 end
  23 + if params[:mark_task_as_ham] && (t = Task.to(profile).find_by_id(params[:mark_task_as_ham]))
  24 + t.ham!
  25 + end
20 26 if request.xhr?
21 27 json_response(true)
22 28 else
... ... @@ -28,7 +34,8 @@ class SpamController < MyProfileController
28 34 return
29 35 end
30 36  
31   - @spam = profile.comments_received.spam.paginate({:page => params[:page]})
  37 + @comment_spam = profile.comments_received.spam.paginate({:page => params[:comments_page]})
  38 + @task_spam = Task.to(profile).spam.paginate({:page => params[:tasks_page]})
32 39 end
33 40  
34 41 protected
... ...
app/controllers/my_profile/tasks_controller.rb
... ... @@ -4,12 +4,12 @@ class TasksController < MyProfileController
4 4  
5 5 def index
6 6 @filter = params[:filter_type].blank? ? nil : params[:filter_type]
7   - @tasks = Task.to(profile).pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
  7 + @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
8 8 @failed = params ? params[:failed] : {}
9 9 end
10 10  
11 11 def processed
12   - @tasks = Task.to(profile).closed.sort_by(&:created_at)
  12 + @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at)
13 13 end
14 14  
15 15 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ]
... ... @@ -57,7 +57,7 @@ class TasksController < MyProfileController
57 57 end
58 58  
59 59 def list_requested
60   - @tasks = Task.find_all_by_requestor_id(profile.id)
  60 + @tasks = Task.without_spam.find_all_by_requestor_id(profile.id)
61 61 end
62 62  
63 63 def ticket_details
... ...
app/models/spammer_logger.rb
... ... @@ -6,6 +6,8 @@ class SpammerLogger < Logger
6 6 if object
7 7 if object.kind_of?(Comment)
8 8 @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n"
  9 + elsif object.kind_of?(SuggestArticle)
  10 + @logger << "[#{Time.now.strftime('%F %T %z')}] SuggestArticle-id: #{object.id} IP: #{spammer_ip}\n"
9 11 end
10 12 else
11 13 @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n"
... ...
app/models/suggest_article.rb
... ... @@ -11,6 +11,21 @@ class SuggestArticle &lt; Task
11 11 settings_items :source, :type => String
12 12 settings_items :source_name, :type => String
13 13 settings_items :highlighted, :type => :boolean, :default => false
  14 + settings_items :ip_address, :type => String
  15 + settings_items :user_agent, :type => String
  16 + settings_items :referrer, :type => String
  17 +
  18 + after_create :schedule_spam_checking
  19 +
  20 + def schedule_spam_checking
  21 + self.delay.check_for_spam
  22 + end
  23 +
  24 + include Noosfero::Plugin::HotSpot
  25 +
  26 + def check_for_spam
  27 + plugins.dispatch(:check_suggest_article_for_spam, self)
  28 + end
14 29  
15 30 def sender
16 31 "#{name} (#{email})"
... ... @@ -61,4 +76,25 @@ class SuggestArticle &lt; Task
61 76 _('You need to login on %{system} in order to approve or reject this article.') % { :system => target.environment.name }
62 77 end
63 78  
  79 + def spam!
  80 + super
  81 + SpammerLogger.log(ip_address, self)
  82 + self.delay.marked_as_spam
  83 + self
  84 + end
  85 +
  86 + def ham!
  87 + super
  88 + self.delay.marked_as_ham
  89 + self
  90 + end
  91 +
  92 + def marked_as_spam
  93 + plugins.dispatch(:suggest_article_marked_as_spam, self)
  94 + end
  95 +
  96 + def marked_as_ham
  97 + plugins.dispatch(:suggest_article_marked_as_ham, self)
  98 + end
  99 +
64 100 end
... ...
app/models/task.rb
... ... @@ -235,6 +235,26 @@ class Task &lt; ActiveRecord::Base
235 235 end
236 236 end
237 237  
  238 + def spam?
  239 + !spam.nil? && spam
  240 + end
  241 +
  242 + def ham?
  243 + !spam.nil? && !spam
  244 + end
  245 +
  246 + def spam!
  247 + self.spam = true
  248 + self.save!
  249 + self
  250 + end
  251 +
  252 + def ham!
  253 + self.spam = false
  254 + self.save!
  255 + self
  256 + end
  257 +
238 258 protected
239 259  
240 260 # This method must be overrided in subclasses, and its implementation must do
... ... @@ -274,6 +294,9 @@ class Task &lt; ActiveRecord::Base
274 294 named_scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] }
275 295 named_scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} }
276 296 named_scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} }
  297 + named_scope :without_spam, :conditions => ['spam IS NULL OR spam = ?', false]
  298 + named_scope :spam, :conditions => ['spam = ?', true]
  299 +
277 300  
278 301 named_scope :to, lambda { |profile|
279 302 environment_condition = nil
... ...
app/views/spam/_comment_spam.rhtml 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %>
  2 +<div id='article'>
  3 + <div class="comments" id="comments_list">
  4 + <ul class="article-comments-list">
  5 + <%= render :partial => 'comment/comment', :collection => @comment_spam %>
  6 + </ul>
  7 + </div>
  8 +</div>
  9 +
  10 +<%= pagination_links @comment_spam, :param_name => :comments_page %>
  11 +
... ...
app/views/spam/_suggest_article.html.erb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<% render :layout => 'task', :locals => { :task => task } do %>
  2 + <% content_for :extra_buttons do %>
  3 + <%= button_to_function('down', _('Show details'), "toggleDetails(this, '#{_('Hide details')}', '#{_('Show details')}')" ) %>
  4 + <% end %>
  5 +
  6 + <% content_for :extra_content do %>
  7 + <ul class="suggest-article-details" style="display: none">
  8 + <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li>
  9 + <li><strong><%=_('Email')%></strong>: <%=task.email%> </li>
  10 + <li><strong><%=_('Source')%></strong>: <%=task.source_name%> </li>
  11 + <li><strong><%=_('Source URL')%></strong>: <%=task.source%> </li>
  12 + <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>
  13 + <li><strong><%=_('Lead')%></strong>: <%=task.article_abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_abstract%> </li>
  14 + <li><strong><%=_('Body')%></strong>:
  15 + <div class='suggest-article-body'>
  16 + <%= task.article_body %>
  17 + </div>
  18 + </li>
  19 + </ul>
  20 + <% end %>
  21 +<% end %>
... ...
app/views/spam/_task.rhtml 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +<div class="task_box" id="task-<%= task.id %>">
  2 + <%= render :partial => 'tasks/task_icon', :locals => {:task => task} %>
  3 + <%= render :partial => 'tasks/task_title', :locals => {:task => task} %>
  4 + <div class="task-information">
  5 + <%= task_information(task) %>
  6 + </div>
  7 +
  8 + <%= yield %> <% # ??? %>
  9 +
  10 + <% button_bar do %>
  11 + <%= button_to_function('new', _('Mark as NOT SPAM'), 'removeTaskBox(this, %s, "%s", "")' % [url_for(:mark_task_as_ham => task.id).to_json, "task-#{task.id}"]) %>
  12 + <%= yield :extra_buttons %>
  13 + <%= button_to_function('delete', _('Remove'), 'removeTaskBox(this, %s, "%s", %s)' % [url_for(:profile => params[:profile], :remove_task => task.id).to_json, "task-#{task.id}", _('Are you sure you want to remove this article suggestion?').to_json]) %>
  14 +
  15 + <% end %>
  16 +
  17 + <%= yield :extra_content %>
  18 +</div>
... ...
app/views/spam/_task_spam.rhtml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +<% @task_spam.each do |t| %>
  2 + <%= render :partial => partial_for_class(t.class), :locals => { :task => t } %>
  3 +<% end %>
  4 +<%= pagination_links @task_spam, :param_name => :tasks_page %>
... ...
app/views/spam/index.rhtml
  1 +<%= stylesheet('tasks') %>
  2 +
1 3 <h1><%= _('Manage SPAM') %></h1>
2 4  
3 5 <% button_bar do %>
... ... @@ -5,16 +7,21 @@
5 7 <% end %>
6 8  
7 9 <%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %>
8   -<div id='article'>
9   - <div class="comments" id="comments_list">
10   - <ul class="article-comments-list">
11   - <%= render :partial => 'comment/comment', :collection => @spam %>
12   - </ul>
13   - </div>
14   -</div>
15 10  
16   -<%= pagination_links @spam %>
  11 +<% if @task_spam.length > 0 %>
  12 + <% tabs = [] %>
  13 + <% tabs << {:title => _('Comment Spam'), :id => 'comment-spam',
  14 + :content => (render :partial => 'comment_spam')} %>
  15 + <% tabs << {:title => _('Task Spam'), :id => 'task-spam',
  16 + :content => (render :partial => 'task_spam') } %>
  17 + <%= render_tabs(tabs) %>
  18 +<% else %>
  19 + <%= render :partial => 'comment_spam' %>
  20 +<% end %>
  21 +
17 22  
18 23 <% button_bar do %>
19 24 <%= button :back, _('Back to control panel'), :controller => :profile_editor %>
20 25 <% end %>
  26 +
  27 +<%= javascript_include_tag 'spam' %>
... ...
app/views/tasks/_task.rhtml
1 1 <div class="task_box" id="task-<%= task.id %>">
2 2  
3   - <div class="task_icon">
4   - <%
5   - icon_info = task.icon
6   - if icon_info[:type] == :profile_image
7   - icon = profile_image(icon_info[:profile], :minor)
8   - elsif icon_info[:type] == :defined_image
9   - icon = "<img src='#{icon_info[:src]}' alt='#{icon_info[:name]}' />"
10   - end
11   - %>
12   - <%=
13   - if icon_info[:url]
14   - link_to(icon, icon_info[:url])
15   - else
16   - icon
17   - end
18   - %>
19   -
20   - </div>
  3 + <%= render :partial => 'task_icon', :locals => {:task => task} %>
21 4  
22 5 <div class="task_decisions">
23 6 <%=
... ... @@ -39,9 +22,7 @@
39 22 %>
40 23 </div><!-- class="task_decisions" -->
41 24  
42   - <strong class="task_title">
43   - <%= task.title %>
44   - </strong>
  25 + <%= render :partial => 'task_title', :locals => {:task => task} %>
45 26  
46 27 <div class="task_information">
47 28 <%= task_information(task) %>
... ...
app/views/tasks/_task_icon.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<%
  2 + icon_info = task.icon
  3 + if icon_info[:type] == :profile_image
  4 + icon = profile_image(icon_info[:profile], :minor)
  5 + elsif icon_info[:type] == :defined_image
  6 + icon = "<img src='#{icon_info[:src]}' alt='#{icon_info[:name]}' />"
  7 + end
  8 +
  9 + if icon_info[:url]
  10 + icon = link_to(icon, icon_info[:url])
  11 + end
  12 +%>
  13 +
  14 +<div class="task_icon">
  15 + <%= icon %>
  16 +</div>
... ...
app/views/tasks/_task_title.rhtml 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +<strong class="task_title">
  2 + <%= task.title %>
  3 +</strong>
... ...
db/migrate/20131011164400_add_spam_to_task.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class AddSpamToTask < ActiveRecord::Migration
  2 + def self.up
  3 + change_table :tasks do |t|
  4 + t.boolean :spam, :default => false
  5 + end
  6 + Task.update_all ["spam = ?", false]
  7 + add_index :tasks, [:spam]
  8 + end
  9 +
  10 + def self.down
  11 + remove_column :tasks, :spam
  12 + end
  13 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,7 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20130711213046) do
  12 +ActiveRecord::Schema.define(:version => 20131011164400) do
13 13  
14 14 create_table "abuse_reports", :force => true do |t|
15 15 t.integer "reporter_id"
... ... @@ -233,6 +233,50 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do
233 233 t.datetime "updated_at"
234 234 end
235 235  
  236 + create_table "custom_forms_plugin_answers", :force => true do |t|
  237 + t.text "value"
  238 + t.integer "field_id"
  239 + t.integer "submission_id"
  240 + end
  241 +
  242 + create_table "custom_forms_plugin_fields", :force => true do |t|
  243 + t.string "name"
  244 + t.string "slug"
  245 + t.string "type"
  246 + t.string "default_value"
  247 + t.string "choices"
  248 + t.float "minimum"
  249 + t.float "maximum"
  250 + t.integer "form_id"
  251 + t.boolean "mandatory", :default => false
  252 + t.boolean "multiple"
  253 + t.boolean "list"
  254 + t.integer "position", :default => 0
  255 + end
  256 +
  257 + create_table "custom_forms_plugin_forms", :force => true do |t|
  258 + t.string "name"
  259 + t.string "slug"
  260 + t.text "description"
  261 + t.integer "profile_id"
  262 + t.datetime "begining"
  263 + t.datetime "ending"
  264 + t.boolean "report_submissions", :default => false
  265 + t.boolean "on_membership", :default => false
  266 + t.string "access"
  267 + t.datetime "created_at"
  268 + t.datetime "updated_at"
  269 + end
  270 +
  271 + create_table "custom_forms_plugin_submissions", :force => true do |t|
  272 + t.string "author_name"
  273 + t.string "author_email"
  274 + t.integer "profile_id"
  275 + t.integer "form_id"
  276 + t.datetime "created_at"
  277 + t.datetime "updated_at"
  278 + end
  279 +
236 280 create_table "delayed_jobs", :force => true do |t|
237 281 t.integer "priority", :default => 0
238 282 t.integer "attempts", :default => 0
... ... @@ -547,8 +591,11 @@ ActiveRecord::Schema.define(:version =&gt; 20130711213046) do
547 591 t.datetime "created_at"
548 592 t.string "target_type"
549 593 t.integer "image_id"
  594 + t.boolean "spam", :default => false
550 595 end
551 596  
  597 + add_index "tasks", ["spam"], :name => "index_tasks_on_spam"
  598 +
552 599 create_table "thumbnails", :force => true do |t|
553 600 t.integer "size"
554 601 t.string "content_type"
... ...
plugins/anti_spam/lib/anti_spam_plugin.rb
... ... @@ -5,7 +5,7 @@ class AntiSpamPlugin &lt; Noosfero::Plugin
5 5 end
6 6  
7 7 def self.plugin_description
8   - _("Checks comments against a spam checking service compatible with the Akismet API")
  8 + _("Tests comments and suggested articles against a spam checking service compatible with the Akismet API")
9 9 end
10 10  
11 11 def self.host_default_setting
... ... @@ -13,30 +13,44 @@ class AntiSpamPlugin &lt; Noosfero::Plugin
13 13 end
14 14  
15 15 def check_comment_for_spam(comment)
16   - if rakismet_call(comment, :spam?)
  16 + if rakismet_call AntiSpamPlugin::CommentWrapper.new(comment), comment.environment, :spam?
17 17 comment.spam = true
18 18 comment.save!
19 19 end
20 20 end
21 21  
22 22 def comment_marked_as_spam(comment)
23   - rakismet_call(comment, :spam!)
  23 + rakismet_call AntiSpamPlugin::CommentWrapper.new(comment), comment.environment, :spam!
24 24 end
25 25  
26 26 def comment_marked_as_ham(comment)
27   - rakismet_call(comment, :ham!)
  27 + rakismet_call AntiSpamPlugin::CommentWrapper.new(comment), comment.environment, :ham!
  28 + end
  29 +
  30 + def check_suggest_article_for_spam(suggest_article)
  31 + if rakismet_call AntiSpamPlugin::SuggestArticleWrapper.new(suggest_article), suggest_article.environment, :spam?
  32 + suggest_article.spam = true
  33 + suggest_article.save!
  34 + end
  35 + end
  36 +
  37 + def suggest_article_marked_as_spam(suggest_article)
  38 + rakismet_call AntiSpamPlugin::SuggestArticleWrapper.new(suggest_article), suggest_article.environment, :spam!
  39 + end
  40 +
  41 + def suggest_article_marked_as_ham(suggest_article)
  42 + rakismet_call AntiSpamPlugin::SuggestArticleWrapper.new(suggest_article), suggest_article.environment, :ham!
28 43 end
29 44  
30 45 protected
31 46  
32   - def rakismet_call(comment, op)
33   - settings = Noosfero::Plugin::Settings.new(comment.environment, self.class)
  47 + def rakismet_call(submission, environment, op)
  48 + settings = Noosfero::Plugin::Settings.new(environment, self.class)
34 49  
35 50 Rakismet.host = settings.host
36 51 Rakismet.key = settings.api_key
37   - Rakismet.url = comment.environment.top_url
  52 + Rakismet.url = environment.top_url
38 53  
39   - submission = AntiSpamPlugin::CommentWrapper.new(comment)
40 54 submission.send(op)
41 55 end
42 56  
... ...
plugins/anti_spam/lib/anti_spam_plugin/suggest_article_wrapper.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class AntiSpamPlugin::SuggestArticleWrapper < Struct.new(:suggest_article)
  2 +
  3 + delegate :name, :email, :article_body, :ip_address, :user_agent, :referrer, :to => :suggest_article
  4 +
  5 + include Rakismet::Model
  6 +
  7 + alias :author :name
  8 + alias :author_email :email
  9 + alias :user_ip :ip_address
  10 + alias :content :article_body
  11 +
  12 +end
... ...
plugins/anti_spam/test/unit/anti_spam_plugin/suggest_article_wrapper_test.rb 0 → 100644
... ... @@ -0,0 +1,45 @@
  1 +require 'test_helper'
  2 +
  3 +class AntiSpamPluginCommentWrapperTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @suggest_article = SuggestArticle.new(
  7 + :article_body => 'comment body',
  8 + :name => 'author',
  9 + :email => 'foo@example.com',
  10 + :ip_address => '1.2.3.4',
  11 + :user_agent => 'Some Good Browser (I hope)',
  12 + :referrer => 'http://noosfero.org/'
  13 + )
  14 + @wrapper = AntiSpamPlugin::SuggestArticleWrapper.new(@suggest_article)
  15 + end
  16 +
  17 + should 'use Rakismet::Model' do
  18 + assert_includes @wrapper.class.included_modules, Rakismet::Model
  19 + end
  20 +
  21 + should 'get contents' do
  22 + assert_equal @suggest_article.article_body, @wrapper.content
  23 + end
  24 +
  25 + should 'get author name' do
  26 + assert_equal @suggest_article.name, @wrapper.author
  27 + end
  28 +
  29 + should 'get author email' do
  30 + assert_equal @suggest_article.email, @wrapper.author_email
  31 + end
  32 +
  33 + should 'get IP address' do
  34 + assert_equal @suggest_article.ip_address, @wrapper.user_ip
  35 + end
  36 +
  37 + should 'get User-Agent' do
  38 + assert_equal @suggest_article.user_agent, @wrapper.user_agent
  39 + end
  40 +
  41 + should 'get get Referrer' do
  42 + assert_equal @suggest_article.referrer, @wrapper.referrer
  43 + end
  44 +
  45 +end
... ...
plugins/anti_spam/test/unit/anti_spam_plugin_test.rb
... ... @@ -7,6 +7,11 @@ class AntiSpamPluginTest &lt; ActiveSupport::TestCase
7 7 article = fast_create(TextileArticle, :profile_id => profile.id)
8 8 @comment = fast_create(Comment, :source_id => article.id, :source_type => 'Article')
9 9  
  10 +
  11 + @suggest_article = SuggestArticle.new(:target_id => profile.id, :target_type => 'Profile', :article_name => 'article', :article_body => 'lorem ipsum', :email => 'invalid@example.com', :name => 'article')
  12 +
  13 + @suggest_article.save!
  14 +
10 15 @settings = Noosfero::Plugin::Settings.new(@comment.environment, AntiSpamPlugin)
11 16 @settings.api_key = 'b8b80ddb8084062d0c9119c945ce3bc3'
12 17 @settings.save!
... ... @@ -23,14 +28,32 @@ class AntiSpamPluginTest &lt; ActiveSupport::TestCase
23 28 assert @comment.spam
24 29 end
25 30  
26   - should 'report spam' do
  31 + should 'report comment spam' do
27 32 AntiSpamPlugin::CommentWrapper.any_instance.expects(:spam!)
28 33 @plugin.comment_marked_as_spam(@comment)
29 34 end
30 35  
31   - should 'report ham' do
  36 + should 'report comment ham' do
32 37 AntiSpamPlugin::CommentWrapper.any_instance.expects(:ham!)
33 38 @plugin.comment_marked_as_ham(@comment)
34 39 end
35 40  
  41 + should 'check for spam and mark suggest_article as spam if server says it is spam' do
  42 + AntiSpamPlugin::SuggestArticleWrapper.any_instance.expects(:spam?).returns(true)
  43 + @suggest_article.expects(:save!)
  44 +
  45 + @plugin.check_suggest_article_for_spam(@suggest_article)
  46 + assert @suggest_article.spam
  47 + end
  48 +
  49 + should 'report suggest_article spam' do
  50 + AntiSpamPlugin::SuggestArticleWrapper.any_instance.expects(:spam!)
  51 + @plugin.suggest_article_marked_as_spam(@suggest_article)
  52 + end
  53 +
  54 + should 'report suggest_article ham' do
  55 + AntiSpamPlugin::SuggestArticleWrapper.any_instance.expects(:ham!)
  56 + @plugin.suggest_article_marked_as_ham(@suggest_article)
  57 + end
  58 +
36 59 end
... ...
public/javascripts/spam.js 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +function removeTaskBox(button, url, task_box_id, msg) {
  2 + var $ = jQuery;
  3 + if (msg && !confirm(msg)) {
  4 + return;
  5 + }
  6 + button = $(button);
  7 + button.addClass('task-button-loading');
  8 + $.post(url, function (data) {
  9 + if (data.ok) {
  10 + $('#' + task_box_id).slideUp();
  11 + } else {
  12 + button.removeClass('task-button-loading');
  13 + button.addClass('task-button-failure');
  14 + }
  15 + });
  16 +}
  17 +
  18 +function toggleDetails(link, msg_hide, msg_show) {
  19 + var $ = jQuery;
  20 + $(link).toggleClass('icon-up icon-down');
  21 + details = $(link).closest('.task_box').find('.suggest-article-details');
  22 + if (details.css('display') == 'none') {
  23 + link.innerHTML = msg_hide;
  24 + } else {
  25 + link.innerHTML = msg_show;
  26 + }
  27 + details.slideToggle();
  28 +}
... ...
test/functional/spam_controller_test.rb
... ... @@ -4,37 +4,55 @@ class SpamControllerTest &lt; ActionController::TestCase
4 4  
5 5 def setup
6 6 @profile = create_user.person
7   - @article = fast_create(TextileArticle, :profile_id => @profile.id)
8   - @spam = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com')
9 7  
  8 + @community = fast_create(Community, :name => 'testcommunity')
  9 + @community.add_admin(@profile)
  10 + @article = fast_create(TextileArticle, :profile_id => @community.id)
  11 + @spam_comment = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com')
  12 +
  13 + @spam_suggest_article = SuggestArticle.create!(:name => 'spammer', :article_name => 'Spam article', :email => 'spammer@shady.place', :article_body => "Something you don't need", :target => @community, :spam => true)
10 14 login_as @profile.identifier
11 15 end
12 16  
13   - test "should only list spammy comments" do
  17 + test "should only list spammy comments and spammy suggest articles" do
14 18 ham = fast_create(Comment, :source_id => @article.id)
15 19  
16   - get :index, :profile => @profile.identifier
  20 + get :index, :profile => @community.identifier
17 21  
18   - assert_equivalent [@spam], assigns(:spam)
  22 + assert_equivalent [@spam_comment], assigns(:comment_spam)
  23 + assert_equivalent [@spam_suggest_article], assigns(:task_spam)
19 24 end
20 25  
21 26 test "should mark comments as ham" do
22   - post :index, :profile => @profile.identifier, :mark_comment_as_ham => @spam.id
  27 + post :index, :profile => @community.identifier, :mark_comment_as_ham => @spam_comment.id
  28 +
  29 + @spam_comment.reload
  30 + assert @spam_comment.ham?
  31 + end
  32 +
  33 + test "should mark suggest article as ham" do
  34 + post :index, :profile => @community.identifier, :mark_task_as_ham => @spam_suggest_article.id
23 35  
24   - @spam.reload
25   - assert @spam.ham?
  36 + @spam_suggest_article.reload
  37 + assert @spam_suggest_article.ham?
26 38 end
27 39  
28 40 test "should remove comments" do
29   - post :index, :profile => @profile.identifier, :remove_comment => @spam.id
  41 + post :index, :profile => @community.identifier, :remove_comment => @spam_comment.id
  42 +
  43 + assert !Comment.exists?(@spam_comment.id)
  44 + end
  45 +
  46 + test "should remove suggest articles" do
  47 + post :index, :profile => @community.identifier, :remove_task => @spam_suggest_article.id
30 48  
31   - assert !Comment.exists?(@spam.id)
  49 + assert !SuggestArticle.exists?(@spam_suggest_article.id)
32 50 end
33 51  
34 52 should 'properly render spam that have replies' do
35   - reply_spam = fast_create(Comment, :source_id => @article_id, :reply_of_id => @spam.id)
  53 + reply_spam = fast_create(Comment, :source_id => @article_id, :reply_of_id => @spam_comment.id)
36 54  
37   - get :index, :profile => @profile.identifier
  55 + get :index, :profile => @community.identifier
38 56 assert_response :success
39 57 end
40 58  
... ...
test/functional/tasks_controller_test.rb
... ... @@ -38,6 +38,17 @@ class TasksControllerTest &lt; ActionController::TestCase
38 38 assert_kind_of Array, assigns(:tasks)
39 39 end
40 40  
  41 + should 'list pending tasks without spam' do
  42 + requestor = fast_create(Person)
  43 + task_spam = Task.create!(:requestor => requestor, :target => profile, :spam => true)
  44 + task_ham = Task.create!(:requestor => requestor, :target => profile, :spam => false)
  45 +
  46 + get :index
  47 + assert_response :success
  48 + assert_includes assigns(:tasks), task_ham
  49 + assert_not_includes assigns(:tasks), task_spam
  50 + end
  51 +
41 52 should 'list processed tasks' do
42 53 get :processed
43 54  
... ... @@ -46,6 +57,17 @@ class TasksControllerTest &lt; ActionController::TestCase
46 57 assert_kind_of Array, assigns(:tasks)
47 58 end
48 59  
  60 + should 'list processed tasks without spam' do
  61 + requestor = fast_create(Person)
  62 + task_spam = Task.create!(:status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => true)
  63 + task_ham = Task.create!(:status => Task::Status::FINISHED, :requestor => requestor, :target => profile, :spam => false)
  64 +
  65 + get :processed
  66 + assert_response :success
  67 + assert_includes assigns(:tasks), task_ham
  68 + assert_not_includes assigns(:tasks), task_spam
  69 + end
  70 +
49 71 should 'be able to finish a task' do
50 72 t = profile.tasks.build; t.save!
51 73  
... ... @@ -140,6 +162,15 @@ class TasksControllerTest &lt; ActionController::TestCase
140 162 assert_includes assigns(:tasks), task
141 163 end
142 164  
  165 + should 'list tasks that this profile created without spam' do
  166 + task_spam = Ticket.create!(:name => 'test', :requestor => profile, :spam => true)
  167 + task_ham = Ticket.create!(:name => 'test', :requestor => profile, :spam => false)
  168 + get :list_requested, :profile => profile.identifier
  169 +
  170 + assert_includes assigns(:tasks), task_ham
  171 + assert_not_includes assigns(:tasks), task_spam
  172 + end
  173 +
143 174 should 'set target of ticket when creating it' do
144 175 f = create_user('friend').person
145 176 profile.add_friend f
... ...
test/unit/suggest_article_test.rb
... ... @@ -150,5 +150,79 @@ class SuggestArticleTest &lt; ActiveSupport::TestCase
150 150 assert_match(/#{task.name}.*suggested the publication of the article: #{task.subject}/, email.subject)
151 151 end
152 152  
  153 + class EverythingIsSpam < Noosfero::Plugin
  154 + def check_suggest_article_for_spam(suggest_article)
  155 + suggest_article.spam!
  156 + end
  157 + end
  158 +
  159 + should 'delegate spam detection to plugins' do
  160 + Environment.default.enable_plugin(EverythingIsSpam)
  161 +
  162 + t1 = build(SuggestArticle, :target => @profile, :article_name => 'suggested article', :name => 'johndoe', :email => 'johndoe@example.com')
  163 +
  164 + EverythingIsSpam.any_instance.expects(:check_suggest_article_for_spam)
  165 +
  166 + t1.check_for_spam
  167 + end
  168 +
  169 + class SpamNotification < Noosfero::Plugin
  170 + class << self
  171 + attr_accessor :marked_as_spam
  172 + attr_accessor :marked_as_ham
  173 + end
  174 +
  175 + def check_suggest_article_for_spam(c)
  176 + # do nothing
  177 + end
  178 +
  179 + def suggest_article_marked_as_spam(c)
  180 + self.class.marked_as_spam = c
  181 + end
  182 +
  183 + def suggest_article_marked_as_ham(c)
  184 + self.class.marked_as_ham = c
  185 + end
  186 + end
  187 +
  188 + should 'notify plugins of suggest_articles being marked as spam' do
  189 + Environment.default.enable_plugin(SpamNotification)
  190 +
  191 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com')
  192 +
  193 + t.spam!
  194 + process_delayed_job_queue
  195 +
  196 + assert_equal t, SpamNotification.marked_as_spam
  197 + end
  198 +
  199 + should 'notify plugins of suggest_articles being marked as ham' do
  200 + Environment.default.enable_plugin(SpamNotification)
  201 +
  202 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com')
  203 +
  204 + t.ham!
  205 + process_delayed_job_queue
  206 +
  207 + assert_equal t, SpamNotification.marked_as_ham
  208 + end
  209 +
  210 + should 'store User-Agent' do
  211 + t = SuggestArticle.new(:user_agent => 'foo')
  212 + assert_equal 'foo', t.user_agent
  213 + end
  214 +
  215 + should 'store referrer' do
  216 + t = SuggestArticle.new(:referrer => 'bar')
  217 + assert_equal 'bar', t.referrer
  218 + end
  219 +
  220 + should 'log spammer ip after marking comment as spam' do
  221 + t = SuggestArticle.create!(:target => @profile, :article_name => 'suggested article', :name => 'johndoe', :article_body => 'wanna feel my body? my body baaaby', :email => 'johndoe@example.com', :ip_address => '192.168.0.1')
  222 + t.spam!
  223 + log = File.open('log/test_spammers.log')
  224 + assert_match "SuggestArticle-id: #{t.id} IP: 192.168.0.1", log.read
  225 + SpammerLogger.clean_log
  226 + end
153 227  
154 228 end
... ...
test/unit/task_test.rb
... ... @@ -372,6 +372,55 @@ class TaskTest &lt; ActiveSupport::TestCase
372 372 assert_includes Task.closed, canceled
373 373 end
374 374  
  375 + should 'be ham by default' do # ham means not spam
  376 + assert_equal false, Task.create.spam
  377 + end
  378 +
  379 + should 'be able to mark tasks as spam/ham/unknown' do
  380 + t = Task.new
  381 + t.spam = true
  382 + assert t.spam?
  383 + assert !t.ham?
  384 +
  385 + t.spam = false
  386 + assert t.ham?
  387 + assert !t.spam?
  388 +
  389 + t.spam = nil
  390 + assert !t.spam?
  391 + assert !t.ham?
  392 + end
  393 +
  394 + should 'be able to select non-spam tasks' do
  395 + t1 = fast_create(Task)
  396 + t2 = fast_create(Task, :spam => false)
  397 + t3 = fast_create(Task, :spam => true)
  398 +
  399 + assert_equivalent [t1,t2], Task.without_spam
  400 + end
  401 +
  402 + should 'be able to select spam tasks' do
  403 + t1 = fast_create(Task)
  404 + t2 = fast_create(Task, :spam => false)
  405 + t3 = fast_create(Task, :spam => true)
  406 +
  407 + assert_equivalent [t3], Task.spam
  408 + end
  409 +
  410 + should 'be able to mark as spam' do
  411 + t1 = fast_create(Task)
  412 + t1.spam!
  413 + t1.reload
  414 + assert t1.spam?
  415 + end
  416 +
  417 + should 'be able to mark as ham' do
  418 + t1 = fast_create(Task)
  419 + t1.ham!
  420 + t1.reload
  421 + assert t1.ham?
  422 + end
  423 +
375 424 protected
376 425  
377 426 def sample_user
... ...