Skip to content

Commit

Permalink
working on spam protection
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Fuchs committed Jul 12, 2008
1 parent b97e60b commit 537e183
Show file tree
Hide file tree
Showing 29 changed files with 281 additions and 160 deletions.
3 changes: 0 additions & 3 deletions config/initializers/spam_engines.rb

This file was deleted.

12 changes: 11 additions & 1 deletion public/javascripts/admin/admin.js
Expand Up @@ -9,8 +9,18 @@ SiteSelect.change = function(event) {
location.href = event.element().getValue();
}

var SiteSpamOptions = Class.create();
SiteSpamOptions.change = function(event) {
var engine = event.element().value
$$('.site_spam_settings').each(function(element){
element.removeClassName('active');
})
$('site_spam_settings_' + engine.toLowerCase()).addClassName('active');
}

Event.addBehavior({
'#site-select': function() { Event.observe(this, 'change', SiteSelect.change.bind(this)); },
'#site-select': function() { Event.observe(this, 'change', SiteSelect.change.bind(this)); },
'.site_spam_options_engine': function() { Event.observe(this, 'change', SiteSpamOptions.change.bind(this)); },
'#comments-filter': function() { Event.observe(this, 'change', Comments.filter.bind(this)); }
})

Expand Down
7 changes: 7 additions & 0 deletions public/stylesheets/admin/form.css
Expand Up @@ -88,6 +88,13 @@ p.buttons {
padding: 3px;
}

.site_spam_settings {
display: none;
}
.site_spam_settings.active {
display: block;
}

/* errors */

.field_with_error input,
Expand Down
7 changes: 7 additions & 0 deletions spec/fixtures/anonymouses.yml
@@ -0,0 +1,7 @@
an_anonymous:
name: anonymous
email: anonymous@email.org
homepage: http://www.example.org
agent: the-agent
ip: 1.1.1.1
referer: the-referer
8 changes: 8 additions & 0 deletions spec/fixtures/comments.yml
@@ -0,0 +1,8 @@
a_comment:
body: comment body
site: site_1
section: home
author: an_anonymous,
author_type: Anonymous,
commentable: an_article
commentable_type: Article,
15 changes: 15 additions & 0 deletions spec/models/site_spec.rb
Expand Up @@ -29,6 +29,10 @@
Site.serialized_attributes.should include('permissions')
end

it "serializes the spam options" do
Site.serialized_attributes.should include('spam_options')
end

it 'has default permissions' do
Site.default_permissions.should ==
{ :site => { :show => :admin, :create => :superuser, :update => :admin, :destroy => :superuser, :manage => :admin },
Expand Down Expand Up @@ -113,4 +117,15 @@
@site.should validate_presence_of(:title)
end
end

describe "spam_engine:" do
it "should return the None spam engine when none configured" do
Site.new.spam_engine.should be_kind_of(SpamEngine::None)
end

it "should return the Defensio spam engine when spam_options :engine is set to 'defensio'" do
site = Site.new :spam_options => {:engine => "Defensio"}
site.spam_engine.should be_kind_of(SpamEngine::Defensio)
end
end
end
109 changes: 59 additions & 50 deletions spec/models/spam.rb
@@ -1,61 +1,70 @@
require File.dirname(__FILE__) + '/../spec_helper'

describe 'Spam engines' do
fixtures :sites, :sections, :contents
fixtures :sites, :sections, :contents, :comments, :anonymouses

before :each do
@site = sites(:site_1)
@section = sections(:home)
@comment = comments(:a_comment)
@comment.author = anonymouses(:an_anonymous) # wtf
@comment.commentable = contents(:an_article)

@article = contents(:an_article)
@anonymous = Anonymous.new :name => 'anonymous',
:email => 'anonymous@email.org',
:homepage => 'http://www.example.org',
:agent => 'the-agent',
:ip => '1.1.1.1',
:referer => 'the-referer'

@comment = Comment.new :body => 'comment body',
:site_id => @site.id,
:section_id => @section.id,
:section => @section,
:author => @anonymous,
:commentable_type => 'Article',
:commentable_id => @article.id
http = Net::HTTP.new("url")
Net::HTTP.stub!(:new).and_return(http)

@akismet_options = { :permalink => "http://www.example.org/an-article",
:user_ip => '1.1.1.1',
:user_agent => 'the-agent',
:referrer => 'the-referer',
:comment_author => "anonymous",
:comment_author_email => "anonymous@email.org",
:comment_author_url => "http://www.example.org",
:comment_content => "comment body" }

@defensio_options = { :permalink => "http://www.example.org/an-article",
:user_ip => '1.1.1.1',
:referrer => 'the-referer',
:comment_author => "anonymous",
:comment_author_email => "anonymous@email.org",
:comment_author_url => "http://www.example.org",
:comment_content => "comment body",
:article_date => @comment.commentable.published_at,
:comment_type => "comment",
:user_logged_in => nil,
:trusted_user => nil }
end

it "#check_comment on a Section ends up calling #check_comment on the Akismet Viking engine" do
@site.update_attributes :spam_options => {:engine => 'Akismet', 'Akismet' => {:akismet_key => 'key', :akismet_url => 'http://domain.com'}}
options = { :permalink => "http://www.example.org/an-article",
:user_ip => '1.1.1.1',
:user_agent => 'the-agent',
:referrer => 'the-referer',
:comment_author => "anonymous",
:comment_author_email => "anonymous@email.org",
:comment_author_url => "http://www.example.org",
:comment_content => "comment body" }

@comment.section.site.spam_engine.send(:akismet).should_receive(:check_comment).with(options).and_return true
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.spam_info.should == {:spam => false}
end
describe '#check_comment' do
it "approves the comment when the site's spam_option :engine is 'None' and approve_comments is true" do
sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => true}
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.approved?.should be_true
end

it "does not approve the comment when the site's spam_option :engine is 'None' and approve_comments is not true" do
sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => false}
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.approved?.should be_false
end

it "calls #check_comment on the None SpamEngine when the site's spam_option :engine is 'None'" do
sites(:site_1).update_attributes :spam_options => {:engine => 'None', :approve_comments => false}
@comment.section.site.spam_engine.should be_instance_of(SpamEngine::None)
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.spam_info.should == {}
end

it "calls #check_comment on the Akismet Viking engine when the site's spam_option :engine is 'Akismet'" do
sites(:site_1).update_attributes :spam_options => {:engine => 'Akismet', 'Akismet' => {:akismet_key => 'key', :akismet_url => 'http://domain.com'}}
@comment.section.site.spam_engine.send(:akismet).should_receive(:check_comment).with(@akismet_options).and_return true
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.spam_info.should == {:spam => false}
end

it "#check_comment on a Section ends up calling #check_comment on the Defensio Viking engine" do
@site.update_attributes :spam_options => {:engine => 'Defensio', 'Defensio' => {:defensio_key => 'key', :defensio_url => 'http://domain.com'}}
options = { :permalink => "http://www.example.org/an-article",
:user_ip => '1.1.1.1',
:referrer => 'the-referer',
:comment_author => "anonymous",
:comment_author_email => "anonymous@email.org",
:comment_author_url => "http://www.example.org",
:comment_content => "comment body",
:article_date => @comment.commentable.published_at,
:comment_type => "comment",
:user_logged_in => nil,
:trusted_user => nil }

@comment.section.site.spam_engine.send(:defensio).should_receive(:check_comment).with(options).and_return :spam => false, :spaminess => 0.0, :signature => 'signature'
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.spam_info.should == {:spam => false, :spaminess => 0.0, :signature => 'signature'}
it "calls #check_comment on the Defensio Viking engine when the site's spam_option :engine is 'Defensio'" do
sites(:site_1).update_attributes :spam_options => {:engine => 'Defensio', 'Defensio' => {:defensio_key => 'key', :defensio_url => 'http://domain.com'}}
@comment.section.site.spam_engine.send(:defensio).should_receive(:check_comment).with(@defensio_options).and_return :spam => false, :spaminess => 0.0, :signature => 'signature'
@comment.check_spam('http://www.example.org/an-article', @comment)
@comment.spam_info.should == {:spam => false, :spaminess => 0.0, :signature => 'signature'}
end
end
end
3 changes: 2 additions & 1 deletion spec/stubs/comment.rb
Expand Up @@ -19,7 +19,8 @@
:frozen? => false,
:role_authorizing => Role.build(:author),
:commentable= => nil,
:check_spam => false
:check_spam => false,
:approved_changed? => false

instance :comment
end
1 change: 1 addition & 0 deletions vendor/engines/adva_cms/app/controllers/base_controller.rb
Expand Up @@ -3,6 +3,7 @@
class BaseController < ApplicationController
class SectionRoutingError < ActionController::RoutingError; end
helper :base, :content, :comments, :users
include ContentHelper # WTF!

include CacheableFlash
include Widgets
Expand Down
2 changes: 1 addition & 1 deletion vendor/engines/adva_cms/app/models/section.rb
Expand Up @@ -77,7 +77,7 @@ def accept_comments?
end

def approve_comments?
true
site.approve_comments?
end

def check_comment(url, comment, options = {})
Expand Down
17 changes: 10 additions & 7 deletions vendor/engines/adva_cms/app/models/site.rb
Expand Up @@ -45,8 +45,7 @@ def recent

validates_presence_of :host, :name, :title

cattr_accessor :multi_sites_enabled, :cache_sweeper_logging, :spam_engines
@@spam_engines = []
cattr_accessor :multi_sites_enabled, :cache_sweeper_logging

class << self
def find_by_host!(host)
Expand All @@ -59,10 +58,6 @@ def find_users_and_superusers(id, options = {})
condition = ["memberships.site_id = ? OR (memberships.site_id IS NULL AND roles.type = ?)", id, 'Role::Superuser']
User.find :all, options.merge(:include => [:roles, :memberships], :conditions => condition)
end

def register_spam_engine(klass)
@@spam_engines << klass.name
end
end

def owner
Expand All @@ -87,8 +82,16 @@ def perma_host
host
end

def approve_comments?
!!spam_options[:approve_comments]
end

def spam_options
read_attribute(:spam_options) || {}
end

def spam_engine
@spam_engine ||= SpamEngine.adapter(self, spam_options || {})
@spam_engine ||= SpamEngine.adapter(self.spam_options)
end

private
Expand Down
18 changes: 17 additions & 1 deletion vendor/engines/adva_cms/app/views/admin/sites/_form.html.erb
Expand Up @@ -32,7 +32,23 @@
<fieldset>
<p>
<%= f.label :comment_filter, 'Comments filter' %>
<span class="hint">When comments are posted, they use this markup</span>
<span class="hint">When comments are posted, they use this markup.</span>
<%= f.select :comment_filter, filter_options %>
</p>
</fieldset>

<h4>Spam protection</h4>
<fieldset>
<h4>Spam detection engine</h4>
<span class="hint">When comments are posted, the following engine is used to check their spam status.</span>
<p>
<% SpamEngine.names.each do |name| %>
<%= radio_button_tag 'site[spam_options][engine]', name, name == @site.spam_engine.name, :class => "site_spam_options_engine" %>
<%= label :site, "spam_options_engine_#{name.downcase}", name, :class => 'inline light' %>
<% end %>
</p>

<% SpamEngine.names.each do |name| %>
<%= render :partial => "admin/spam/#{name.downcase}_settings", :locals => {:active => name == @site.spam_engine.name} %>
<% end %>
</fieldset>
11 changes: 11 additions & 0 deletions vendor/engines/adva_cms/app/views/admin/spam/_akismet_settings.erb
@@ -0,0 +1,11 @@
<div id="site_spam_settings_akismet" class="site_spam_settings <%= 'active' if active %>">
<h4>Settings</h4>
<p>
<label for="site_spam_options_akismet_key">Akismet API Key</label>
<%= text_field_tag "site[spam_options][akismet_key]", @site.spam_options[:akismet_key], :id => 'site_spam_options_akismet_key' %>
</p>
<p>
<label for="site_spam_options_akismet_url">Blog url</label>
<%= text_field_tag "site[spam_options][akismet_url]", @site.spam_options[:akismet_url], :id => 'site_spam_options_akismet_url' %>
</p>
</div>
@@ -0,0 +1,11 @@
<div id="site_spam_settings_defensio" class="site_spam_settings <%= 'active' if active %>">
<h4>Settings</h4>
<p>
<label for="site_spam_options_defensio_key">Defensio API Key</label>
<%= text_field_tag "site[spam_options][defensio_key]", @site.spam_options[:defensio_key], :id => 'site_spam_options_defensio_key' %>
</p>
<p>
<label for="site_spam_options_defensio_url">Blog url</label>
<%= text_field_tag "site[spam_options][defensio_url]", @site.spam_options[:defensio_url], :id => 'site_spam_options_defensio_url' %>
</p>
</div>
@@ -0,0 +1,9 @@
<div id="site_spam_settings_none" class="site_spam_settings <%= 'active' if active %>">
<h4>Settings</h4>
<p>
<%= check_box_tag 'site[spam_options][approve_comments]', "1", @site.approve_comments?, :id => 'site_spam_options_approve_comments' %>
<label class="inline light" for="site_spam_options_approve_comments">
Approve and publish all comments automatically.
</label>
</p>
</div>

This file was deleted.

This file was deleted.

5 changes: 0 additions & 5 deletions vendor/engines/adva_cms/app/views/admin/spam/none.html.erb

This file was deleted.

4 changes: 4 additions & 0 deletions vendor/engines/adva_cms/init.rb
Expand Up @@ -19,3 +19,7 @@
Tag.destroy_unused = true
Tag.class_eval do def to_param; name end end

require 'spam_engine'
require 'spam_engine/none'
require 'spam_engine/akismet'
require 'spam_engine/defensio'
16 changes: 14 additions & 2 deletions vendor/engines/adva_cms/lib/spam_engine.rb
@@ -1,8 +1,20 @@
module SpamEngine
mattr_accessor :adapters
@@adapters = []

class << self
def adapter(site, options = {})
def adapter(options)
name = options[:engine] || 'None'
"SpamEngine::#{name}".constantize.new(site, options[name])
options = (options[name] || {}).merge :approve => options[:approve_comments]
"SpamEngine::#{name}".constantize.new options
end

def register(klass)
@@adapters << klass.name
end

def names
adapters.map &:demodulize
end
end
end

0 comments on commit 537e183

Please sign in to comment.