bradleypriest-mollom 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/lib/mollom/api_compatibility.rb +16 -0
- data/lib/mollom/content_response.rb +68 -0
- data/lib/mollom.rb +215 -0
- data/mollom.gemspec +52 -0
- data/pkg/mollom-0.1.1.gem +0 -0
- data/test/content_response_test.rb +33 -0
- data/test/mollom_test.rb +271 -0
- metadata +67 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Jan De Poorter - Openminds BVBA
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
== Mollom
|
2
|
+
|
3
|
+
This is a Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assessment.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
You can either install the library as a gem
|
8
|
+
gem install mollom
|
9
|
+
|
10
|
+
Or you can get the latest development version from GitHub:
|
11
|
+
git clone git://github.com/DefV/ruby-mollom.git
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
After you have requested a public/private key-pair from Mollom (on http://www.mollom.com), you can start using this class.
|
16
|
+
|
17
|
+
require 'rubygems'
|
18
|
+
require 'mollom'
|
19
|
+
|
20
|
+
m = Mollom.new(:private_key => 'your-private-key', :public_key => 'your-public-key')
|
21
|
+
|
22
|
+
content = m.check_content(:post_title => 'Mollem is an open API',
|
23
|
+
:post_body => "Lorem Ipsum dolor...",
|
24
|
+
:author_name => 'Jan De Poorter',
|
25
|
+
:author_url => 'http://workswithruby.com')
|
26
|
+
if content.spam?
|
27
|
+
puts "You, sir, are a spammer.. Goodbye!"
|
28
|
+
elsif content.unsure?
|
29
|
+
# possible spam, possible ham, show CAPTCHA
|
30
|
+
puts "CAPTCHA: " + m.image_captcha(:session_id => content.session_id)["url"]
|
31
|
+
|
32
|
+
captcha_correct = m.check_captcha(:session_id => content.session_id, :solution => STDIN.gets.chomp)
|
33
|
+
else
|
34
|
+
puts "The post is perfect! No spam!"
|
35
|
+
end
|
36
|
+
|
37
|
+
Copyright (c) 2008 Jan De Poorter - Openminds BVBA, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gemspec|
|
8
|
+
gemspec.name = "bradleypriest-mollom"
|
9
|
+
gemspec.summary = "Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment."
|
10
|
+
gemspec.description = "Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment."
|
11
|
+
gemspec.email = "mollom@openminds.be"
|
12
|
+
gemspec.homepage = "http://mollom.rubyforge.com"
|
13
|
+
gemspec.authors = ["Jan De Poorter"]
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::TestTask.new do |t|
|
21
|
+
t.libs << "test"
|
22
|
+
t.test_files = FileList['test/*_test.rb']
|
23
|
+
t.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
Rake::RDocTask.new { |rdoc|
|
27
|
+
rdoc.rdoc_dir = 'docs'
|
28
|
+
rdoc.title = "Mollom -- Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment."
|
29
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
30
|
+
rdoc.options << '--charset' << 'utf-8'
|
31
|
+
rdoc.rdoc_files.include('README.rdoc')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
}
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.3
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Mollom
|
2
|
+
module ApiCompatibility
|
3
|
+
def self.included base
|
4
|
+
base.class_eval do
|
5
|
+
alias checkContent check_content
|
6
|
+
alias getImageCaptcha image_captcha
|
7
|
+
alias getAudioCaptcha audio_captcha
|
8
|
+
alias checkCaptcha valid_captcha?
|
9
|
+
alias verifyKey key_ok?
|
10
|
+
alias getStatistics statistics
|
11
|
+
alias sendFeedback send_feedback
|
12
|
+
alias detectLanguage language_for
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Mollom
|
2
|
+
class ContentResponse
|
3
|
+
attr_reader :session_id
|
4
|
+
|
5
|
+
# An assessment of the content's quality, between 0 and 1; 0 being very low, 1 being high quality if specified in check_content checks
|
6
|
+
attr_reader :quality
|
7
|
+
|
8
|
+
# An assessment of the content's profanity level, between 0 and 1; 0 being non-profane, 1 being very profane if specified in check_content checks
|
9
|
+
attr_reader :profanity
|
10
|
+
|
11
|
+
# An assessment of the content's sentiment, between 0 and 1; 0 being a very negative sentiment, 1 being a very positive sentiment if specified in check_content checks
|
12
|
+
attr_reader :sentiment
|
13
|
+
|
14
|
+
# a list of structs containing pairs of language and confidence values if specified in checkContent checks
|
15
|
+
attr_reader :language
|
16
|
+
|
17
|
+
Unknown = 0
|
18
|
+
Ham = 1
|
19
|
+
Spam = 2
|
20
|
+
Unsure = 3
|
21
|
+
|
22
|
+
# This class should only be initialized from within the +check_content+ command.
|
23
|
+
def initialize(hash)
|
24
|
+
@hash = hash
|
25
|
+
@spam_response = hash["spam"]
|
26
|
+
@session_id = hash["session_id"]
|
27
|
+
@quality = hash["quality"]
|
28
|
+
@profanity = hash["profanity"]
|
29
|
+
@sentiment = hash["sentiment"]
|
30
|
+
@language = hash["language"]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is the content Spam?
|
34
|
+
def spam?
|
35
|
+
@spam_response == Spam
|
36
|
+
end
|
37
|
+
|
38
|
+
# Is the content Ham?
|
39
|
+
def ham?
|
40
|
+
@spam_response == Ham
|
41
|
+
end
|
42
|
+
|
43
|
+
# is Mollom unsure about the content?
|
44
|
+
def unsure?
|
45
|
+
@spam_response == Unsure
|
46
|
+
end
|
47
|
+
|
48
|
+
# is the content unknown?
|
49
|
+
def unknown?
|
50
|
+
@spam_response == Unknown
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns 'unknown', 'ham', 'unsure' or 'spam', depending on what the content is.
|
54
|
+
def to_s
|
55
|
+
case @spam_response
|
56
|
+
when Unknown then 'unknown'
|
57
|
+
when Ham then 'ham'
|
58
|
+
when Unsure then 'unsure'
|
59
|
+
when Spam then 'spam'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the original hash for testing
|
64
|
+
def to_hash
|
65
|
+
@hash
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/mollom.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
require 'mollom/content_response'
|
5
|
+
require 'mollom/api_compatibility'
|
6
|
+
|
7
|
+
# Mollom API requires this to change, but this gives a warning!
|
8
|
+
# XMLRPC::Client::USER_AGENT = "Ruby Mollom/0.1"
|
9
|
+
|
10
|
+
class Mollom
|
11
|
+
API_VERSION = '1.0'
|
12
|
+
STATIC_SERVER_LIST = [{:proto => 'http', :host => 'xmlrpc3.mollom.com'},
|
13
|
+
{:proto => 'http', :host => 'xmlrpc2.mollom.com'},
|
14
|
+
{:proto => 'http', :host => 'xmlrpc1.mollom.com'}].freeze
|
15
|
+
|
16
|
+
module Errors
|
17
|
+
Standard = 1000
|
18
|
+
Refresh = 1100
|
19
|
+
TooBusy = 1200
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :private_key, :public_key
|
23
|
+
|
24
|
+
# Creates a new Mollom object. Takes +private_key+ and +public_key+ as keys.
|
25
|
+
#
|
26
|
+
# Mollom.new(:private_key => 'qopzalnzanzajlazjna', :public_key => 'aksakzaddazidzaodjaz')
|
27
|
+
# # => #<Mollom:0x5b6454 @public_key="aksakzaddazidzaodjaz", @private_key="qopzalnzanzajlazjna">
|
28
|
+
|
29
|
+
def initialize options = {}
|
30
|
+
@private_key = options[:private_key]
|
31
|
+
@public_key = options[:public_key]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks the content whether it is spam, ham (not spam), or undecided, and gives a quality assessment of the content.
|
35
|
+
# Possible content keys are:
|
36
|
+
# session_id # => If you allready have a session_id
|
37
|
+
# post_title # => The title
|
38
|
+
# post_body # => The main content of the post.
|
39
|
+
# author_name # => The name of the post author
|
40
|
+
# author_url # => The url the author enters
|
41
|
+
# author_mail # => The author's email address
|
42
|
+
# author_ip # => The author's IP address
|
43
|
+
# author_openid # => The author's OpenID
|
44
|
+
# author_id # => The author's ID
|
45
|
+
# checks # => A comma-separated list of checks. Available checks include 'spam', 'quality', 'profanity', 'sentiment' and 'language'. E.g. 'spam,quality,sentiment'
|
46
|
+
#
|
47
|
+
# Only the +post_body+ key is required, all other keys are optional.
|
48
|
+
# This function returns a ContentResponse object.
|
49
|
+
#
|
50
|
+
# response = mollom.check_content :post_title => 'Mollom rules!',
|
51
|
+
# :post_body => 'I think that mollom is so cool!',
|
52
|
+
# :author_name => 'Jan De Poorter',
|
53
|
+
# :author_url => 'http://www.openminds.be'
|
54
|
+
# response.spam? # => false
|
55
|
+
# response.ham? # => true
|
56
|
+
def check_content content = {}
|
57
|
+
ContentResponse.new(send_command('mollom.checkContent', content))
|
58
|
+
end
|
59
|
+
|
60
|
+
# Requests an Image captcha from Mollom. It takes the optional <tt>session_id</tt> and <tt>author_ip</tt> keys, if you allready have a session.
|
61
|
+
# It returns a hash with the URL where the captcha can be found, and the session_id, to keep track of the current session (Needed later in <tt>Mollom#check_captcha</tt>)
|
62
|
+
#
|
63
|
+
# captcha = mollom.image_captcha :author_ip => '172.16.0.1'
|
64
|
+
# captcha['url'] # => http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.png
|
65
|
+
# captcha['session_id'] # => a9616e6b4cd6a81ecdd509fa624d895d
|
66
|
+
def image_captcha info = {}
|
67
|
+
send_command('mollom.getImageCaptcha', info)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Requests an Audio captcha from Mollom. It takes the optional +session_id+ and +author_ip+ keys, if you allready have a session.
|
71
|
+
# It returns a hash with the URL where the captcha can be found, and the session_id, to keep track of the current session (Needed later in <tt>Mollom#check_captcha</tt>)
|
72
|
+
#
|
73
|
+
# captcha = mollom.audio_captcha :author_ip => '172.16.0.2', :session_id => 'a9616e6b4cd6a81ecdd509fa624d895d'
|
74
|
+
# captcha['url'] # => http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.mp3
|
75
|
+
# captcha['session_id'] # => a9616e6b4cd6a81ecdd509fa624d895d
|
76
|
+
def audio_captcha info = {}
|
77
|
+
send_command('mollom.getAudioCaptcha', info)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Checks with mollom if the given captcha (by the user) is correct. Takes +session_id+ and +solution+ keys. Both keys are required.
|
81
|
+
# Returns true if the captcha is valid, false if it is incorrect
|
82
|
+
#
|
83
|
+
# captcha = mollom.image_captcha :author_ip => '172.16.0.1'
|
84
|
+
# # show to user... input from user
|
85
|
+
# return = mollom.valid_captcha? :session_id => captcha['session_id'], :solution => 'abcDe9'
|
86
|
+
# return # => true
|
87
|
+
def valid_captcha? info = {}
|
88
|
+
send_command('mollom.checkCaptcha', info)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Standard check to see if your public/private keypair are recognized. Takes no options
|
92
|
+
def key_ok?
|
93
|
+
send_command('mollom.verifyKey')
|
94
|
+
rescue XMLRPC::FaultException
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
# Gets some statistics from Mollom about your site.
|
99
|
+
#
|
100
|
+
# The type has to be passed. Possible types:
|
101
|
+
# total_days
|
102
|
+
# total_accepted
|
103
|
+
# total_rejected
|
104
|
+
# yesterday_accepted
|
105
|
+
# yesterday_rejected
|
106
|
+
# today_accepted
|
107
|
+
# today_rejected
|
108
|
+
#
|
109
|
+
# mollom.statistics :type => 'total_accepted' # => 123
|
110
|
+
def statistics options = {}
|
111
|
+
send_command('mollom.getStatistics', options)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Send feedback to Mollom about a certain content. Required keys are +session_id+ and +feedback+.
|
115
|
+
#
|
116
|
+
# Feedback can be any of
|
117
|
+
# spam
|
118
|
+
# profanity
|
119
|
+
# low-quality
|
120
|
+
# unwanted
|
121
|
+
#
|
122
|
+
# mollom.send_feedback :session_id => 'a9616e6b4cd6a81ecdd509fa624d895d', :feedback => 'unwanted'
|
123
|
+
def send_feedback feedback = {}
|
124
|
+
send_command('mollom.sendFeedback', feedback)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Gets language of input text.
|
128
|
+
#
|
129
|
+
# mollom.language_for 'This is my text'
|
130
|
+
def language_for text
|
131
|
+
send_command('mollom.detectLanguage', :text => text)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Gets a list of servers from Mollom. You should cache this information in your application in a temporary file or in a database. You can set this with Mollom#server_list=
|
135
|
+
#
|
136
|
+
# Takes an optional parameter +refresh+, which resets the cached value.
|
137
|
+
#
|
138
|
+
# mollom.server_list
|
139
|
+
# # => [{:proto=>"http", :host=>"88.151.243.81"}, {:proto=>"http", :host=>"82.103.131.136"}]
|
140
|
+
def server_list refresh = false
|
141
|
+
return @server_list if @server_list && !refresh
|
142
|
+
STATIC_SERVER_LIST.each do |static_server|
|
143
|
+
@server_list = get_server_list_from(static_server)
|
144
|
+
return @server_list if @server_list
|
145
|
+
end
|
146
|
+
# Should have returned a server_list here..
|
147
|
+
raise(Error.new("Can't get mollom server-list"))
|
148
|
+
end
|
149
|
+
|
150
|
+
# Sets the server list used to contact Mollom. This should be used to set the list of cached servers.
|
151
|
+
#
|
152
|
+
# If you try to set a faulty server list, the function will silently fail, so we can get the server-list from Mollom.
|
153
|
+
def server_list=(list)
|
154
|
+
# Check if we get an actual serverlist-array
|
155
|
+
if list.is_a?(Array) && list.all? {|hash| hash.has_key?(:host) && hash.has_key?(:proto) }
|
156
|
+
@server_list = list
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
def get_server_list_from(server)
|
162
|
+
XMLRPC::Client.new(server[:host], "/#{API_VERSION}").call('mollom.getServerList', authentication_hash).collect do |server|
|
163
|
+
proto, ip = server.split('://')
|
164
|
+
{:proto => proto, :host => ip}
|
165
|
+
end
|
166
|
+
rescue StandardError, Exception
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def send_command(command, data = {})
|
171
|
+
server_list.each do |server|
|
172
|
+
begin
|
173
|
+
client = XMLRPC::Client.new(server[:host], "/#{API_VERSION}")
|
174
|
+
return client.call(command, data.merge(authentication_hash))
|
175
|
+
# TODO: Rescue more stuff (Connection Timeout and such)
|
176
|
+
rescue RuntimeError
|
177
|
+
next
|
178
|
+
rescue XMLRPC::FaultException => error
|
179
|
+
case error.faultCode
|
180
|
+
when Errors::Standard
|
181
|
+
raise Error.new(error.faultString)
|
182
|
+
when Errors::Refresh # Refresh server list please!
|
183
|
+
# we take this one out of our loop
|
184
|
+
raise
|
185
|
+
when Errors::TooBusy # Server is too busy, take the next one
|
186
|
+
next
|
187
|
+
else
|
188
|
+
next
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
raise Mollom::NoAvailableServers
|
193
|
+
rescue XMLRPC::FaultException
|
194
|
+
# We know it is Errors::Refresh
|
195
|
+
server_list(true)
|
196
|
+
retry
|
197
|
+
end
|
198
|
+
|
199
|
+
# Creates a HMAC-SHA1 Hash with the current timestamp, a nonce, and your private key.
|
200
|
+
def authentication_hash
|
201
|
+
now = Time.now.gmtime.strftime('%Y-%m-%dT%H:%M:%S.000+0000')
|
202
|
+
nonce = Kernel.rand(2**31) # Random signed int
|
203
|
+
|
204
|
+
hash = Base64.encode64(
|
205
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @private_key, "#{now}:#{nonce}:#{@private_key}")
|
206
|
+
).chomp
|
207
|
+
|
208
|
+
return :public_key=> @public_key, :time => now, :hash => hash, :nonce => nonce
|
209
|
+
end
|
210
|
+
|
211
|
+
class Error < StandardError; end
|
212
|
+
class NoAvailableServers < Error; end
|
213
|
+
|
214
|
+
include ApiCompatibility
|
215
|
+
end
|
data/mollom.gemspec
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{mollom}
|
8
|
+
s.version = "0.2.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jan De Poorter"]
|
12
|
+
s.date = %q{2010-07-26}
|
13
|
+
s.description = %q{Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment.}
|
14
|
+
s.email = %q{mollom@openminds.be}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"lib/mollom.rb",
|
25
|
+
"lib/mollom/api_compatibility.rb",
|
26
|
+
"lib/mollom/content_response.rb",
|
27
|
+
"mollom.gemspec",
|
28
|
+
"pkg/mollom-0.1.1.gem",
|
29
|
+
"test/content_response_test.rb",
|
30
|
+
"test/mollom_test.rb"
|
31
|
+
]
|
32
|
+
s.homepage = %q{http://mollom.rubyforge.com}
|
33
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
34
|
+
s.require_paths = ["lib"]
|
35
|
+
s.rubygems_version = %q{1.3.7}
|
36
|
+
s.summary = %q{Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment.}
|
37
|
+
s.test_files = [
|
38
|
+
"test/content_response_test.rb",
|
39
|
+
"test/mollom_test.rb"
|
40
|
+
]
|
41
|
+
|
42
|
+
if s.respond_to? :specification_version then
|
43
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
else
|
48
|
+
end
|
49
|
+
else
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
Binary file
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "mollom"
|
4
|
+
|
5
|
+
class TestContentResponse < Test::Unit::TestCase
|
6
|
+
def test_spam
|
7
|
+
cr = Mollom::ContentResponse.new('spam' => 2, 'session_id' => '1', 'quality' => '10')
|
8
|
+
assert cr.spam?
|
9
|
+
assert !cr.ham?
|
10
|
+
assert_equal 'spam', cr.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_ham
|
14
|
+
cr = Mollom::ContentResponse.new('spam' => 1, 'session_id' => '1', 'quality' => '10')
|
15
|
+
assert cr.ham?
|
16
|
+
assert !cr.spam?
|
17
|
+
assert_equal 'ham', cr.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_unknown
|
21
|
+
cr = Mollom::ContentResponse.new('spam' => 0, 'session_id' => '1', 'quality' => '10')
|
22
|
+
assert cr.unknown?
|
23
|
+
assert !cr.unsure?
|
24
|
+
assert_equal 'unknown', cr.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_unsure
|
28
|
+
cr = Mollom::ContentResponse.new('spam' => 3, 'session_id' => '1', 'quality' => '10')
|
29
|
+
assert cr.unsure?
|
30
|
+
assert !cr.unknown?
|
31
|
+
assert_equal 'unsure', cr.to_s
|
32
|
+
end
|
33
|
+
end
|
data/test/mollom_test.rb
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
require 'mollom'
|
6
|
+
|
7
|
+
class Mollom
|
8
|
+
# Unprivate all methods
|
9
|
+
public :authentication_hash
|
10
|
+
public :server_list
|
11
|
+
public :send_command
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestMollom < Test::Unit::TestCase
|
15
|
+
def setup
|
16
|
+
@mollom = Mollom.new(:private_key => 'xxxxxxxxx', :public_key => 'yyyyyyyyy')
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_initialize
|
20
|
+
assert_equal 'xxxxxxxxx', @mollom.private_key
|
21
|
+
assert_equal 'yyyyyyyyy', @mollom.public_key
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_authentication_hash
|
25
|
+
time = mock
|
26
|
+
time.expects(:strftime).with('%Y-%m-%dT%H:%M:%S.000+0000').returns('2008-04-01T13:54:26.000+0000')
|
27
|
+
Time.expects(:now).returns(stub(:gmtime => time))
|
28
|
+
Kernel.expects(:rand).with(2**31).returns(42)
|
29
|
+
hash = @mollom.authentication_hash
|
30
|
+
assert_equal("oWN15TqrbLVdTAgcuDmofskaNyM=", hash[:hash])
|
31
|
+
assert_equal('yyyyyyyyy', hash[:public_key])
|
32
|
+
assert_equal('2008-04-01T13:54:26.000+0000', hash[:time])
|
33
|
+
assert_equal(42, hash[:nonce])
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_server_list
|
37
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc3.mollom.com', :proto => 'http').returns([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}])
|
38
|
+
assert_equal [{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}], @mollom.server_list
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_server_list_with_first_server_bad
|
42
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc3.mollom.com', :proto => 'http').returns(nil)
|
43
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc2.mollom.com', :proto => 'http').returns([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}])
|
44
|
+
assert_equal [{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}], @mollom.server_list
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_server_list_with_all_servers_bad
|
48
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc3.mollom.com', :proto => 'http').returns(nil)
|
49
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc2.mollom.com', :proto => 'http').returns(nil)
|
50
|
+
Mollom.any_instance.expects(:get_server_list_from).with(:host => 'xmlrpc1.mollom.com', :proto => 'http').returns(nil)
|
51
|
+
assert_raise(Mollom::Error) { @mollom.server_list }
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_get_server_list_from_with_ok_return
|
55
|
+
xml_rpc = mock
|
56
|
+
xml_rpc.expects(:call).times(1).with('mollom.getServerList', is_a(Hash)).returns(['http://172.16.0.1', 'http://172.16.0.2', 'https://172.16.0.2'])
|
57
|
+
XMLRPC::Client.stubs(:new).with('xmlrpc.mollom.com', '/1.0').returns(xml_rpc)
|
58
|
+
assert_equal([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}], @mollom.send(:get_server_list_from, {:host => 'xmlrpc.mollom.com', :proto => 'http'}))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_get_server_list_from_with_raising_return
|
62
|
+
xml_rpc = mock
|
63
|
+
xml_rpc.expects(:call).times(1).with('mollom.getServerList', is_a(Hash)).raises(XMLRPC::FaultException.new(1000, "Broken mollom"))
|
64
|
+
XMLRPC::Client.stubs(:new).with('xmlrpc.mollom.com', '/1.0').returns(xml_rpc)
|
65
|
+
assert_equal(nil, @mollom.send(:get_server_list_from, {:host => 'xmlrpc.mollom.com', :proto => 'http'}))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_get_server_list_from_with_timemout
|
69
|
+
xml_rpc = mock
|
70
|
+
xml_rpc.expects(:call).times(1).with('mollom.getServerList', is_a(Hash)).raises(Timeout::Error)
|
71
|
+
XMLRPC::Client.stubs(:new).with('xmlrpc.mollom.com', '/1.0').returns(xml_rpc)
|
72
|
+
assert_equal(nil, @mollom.send(:get_server_list_from, {:host => 'xmlrpc.mollom.com', :proto => 'http'}))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_server_list_force_reload
|
76
|
+
Mollom.any_instance.expects(:get_server_list_from).times(2).with(:host => 'xmlrpc3.mollom.com', :proto => 'http').returns([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'https'}])
|
77
|
+
|
78
|
+
@mollom.server_list
|
79
|
+
@mollom.server_list
|
80
|
+
@mollom.server_list
|
81
|
+
@mollom.server_list(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_server_list_setter_with_good_list
|
85
|
+
@mollom.server_list = [{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}]
|
86
|
+
assert_equal [{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}], @mollom.instance_variable_get('@server_list')
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_send_command_with_old_server_list
|
90
|
+
@mollom.server_list = [{:ip => '172.16.0.1', :proto => 'http'}, {:ip => '172.16.0.2', :proto => 'http'}]
|
91
|
+
assert_equal nil, @mollom.instance_variable_get('@server_list')
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_send_command_with_bad_server_list
|
95
|
+
@mollom.server_list = "404 Not Found Bad User Input"
|
96
|
+
assert_equal nil, @mollom.instance_variable_get('@server_list')
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def test_send_command_with_good_server
|
101
|
+
Mollom.any_instance.expects(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}])
|
102
|
+
xml_rpc = mock
|
103
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
104
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
105
|
+
|
106
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def test_send_command_with_bad_http_response
|
111
|
+
Mollom.any_instance.expects(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}])
|
112
|
+
xml_rpc = mock
|
113
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(RuntimeError.new('HTTP-Error: 302 Found'))
|
114
|
+
xml_rpc2 = mock
|
115
|
+
xml_rpc2.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
116
|
+
|
117
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
118
|
+
XMLRPC::Client.expects(:new).with('172.16.0.2', '/1.0').returns(xml_rpc2)
|
119
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_send_command_with_bad_server
|
123
|
+
Mollom.any_instance.expects(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}, {:host => '172.16.0.2', :proto => 'http'}])
|
124
|
+
xml_rpc = mock
|
125
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1200, "Redirect"))
|
126
|
+
xml_rpc2 = mock
|
127
|
+
xml_rpc2.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
128
|
+
|
129
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
130
|
+
XMLRPC::Client.expects(:new).with('172.16.0.2', '/1.0').returns(xml_rpc2)
|
131
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_send_command_with_reload_exception
|
135
|
+
Mollom.any_instance.stubs(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}], [{:host => '172.16.0.2', :proto => 'http'}])
|
136
|
+
xml_rpc = mock
|
137
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1100, "Refresh"))
|
138
|
+
xml_rpc2 = mock
|
139
|
+
xml_rpc2.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
140
|
+
|
141
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
142
|
+
XMLRPC::Client.expects(:new).with('172.16.0.2', '/1.0').returns(xml_rpc2)
|
143
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_send_command_with_bad_command
|
147
|
+
Mollom.any_instance.expects(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}])
|
148
|
+
xml_rpc = mock
|
149
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1000, "Fault String"))
|
150
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
151
|
+
|
152
|
+
assert_raise(Mollom::Error) { @mollom.send_command('mollom.testMessage', {:options => 'foo'}) }
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_send_command_with_bad_server_and_no_more_available
|
156
|
+
Mollom.any_instance.expects(:server_list).returns([{:host => '172.16.0.1', :proto => 'http'}])
|
157
|
+
xml_rpc = mock
|
158
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1200, "Redirect"))
|
159
|
+
|
160
|
+
XMLRPC::Client.expects(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
161
|
+
|
162
|
+
assert_raise(Mollom::NoAvailableServers) { @mollom.send_command('mollom.testMessage', {:options => 'foo'}) }
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_check_content
|
166
|
+
options = {:author_ip => '172.16.0.1', :post_body => 'Lorem Ipsum'}
|
167
|
+
|
168
|
+
assert_command 'mollom.checkContent', :with => options, :returns => {"spam" => 1, "quality" => 0.40, "session_id" => 1} do
|
169
|
+
cr = @mollom.check_content(options)
|
170
|
+
assert cr.ham?
|
171
|
+
assert_equal 1, cr.session_id
|
172
|
+
assert_equal 0.40, cr.quality
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_check_content_with_checks
|
177
|
+
options = {:author_ip => '172.16.0.1', :post_body => 'Lorem Ipsum', :checks => 'spam,quality,sentiment'}
|
178
|
+
|
179
|
+
assert_command 'mollom.checkContent', :with => options, :returns => {"spam" => 1, "quality" => 0.40, "session_id" => 1, "sentiment" => 0.25, 'profanity' => 0.10 } do
|
180
|
+
cr = @mollom.check_content(options)
|
181
|
+
assert cr.ham?
|
182
|
+
assert_equal 1, cr.session_id
|
183
|
+
assert_equal 0.40, cr.quality
|
184
|
+
assert_equal 0.25, cr.sentiment
|
185
|
+
assert_equal 0.10, cr.profanity
|
186
|
+
assert cr.respond_to? :to_hash
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_image_captcha
|
191
|
+
options = {:author_ip => '172.16.0.1'}
|
192
|
+
|
193
|
+
assert_command 'mollom.getImageCaptcha', :with => options, :returns => {'url' => 'http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.png', 'session_id' => 'a9616e6b4cd6a81ecdd509fa624d895d'} do
|
194
|
+
@mollom.image_captcha(:author_ip => '172.16.0.1')
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_audio_captcha
|
199
|
+
options = {:author_ip => '172.16.0.1'}
|
200
|
+
|
201
|
+
assert_command 'mollom.getAudioCaptcha', :with => options, :returns => {'url' => 'http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.mp3', 'session_id' => 'a9616e6b4cd6a81ecdd509fa624d895d'} do
|
202
|
+
@mollom.audio_captcha(options)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_valid_captcha
|
207
|
+
options = {:session_id => 'a9616e6b4cd6a81ecdd509fa624d895d', :solution => 'foo'}
|
208
|
+
|
209
|
+
assert_command 'mollom.checkCaptcha', :with => options, :returns => true do
|
210
|
+
assert @mollom.valid_captcha?(options)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_key_ok
|
215
|
+
assert_command 'mollom.verifyKey', :returns => true do
|
216
|
+
assert @mollom.key_ok?
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_invalid_key
|
221
|
+
assert_command 'mollom.verifyKey', :raises => internal_server_error do
|
222
|
+
assert !@mollom.key_ok?
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_statistics
|
227
|
+
assert_command 'mollom.getStatistics', :with => {:type => 'total_accepted'}, :returns => 12 do
|
228
|
+
@mollom.statistics(:type => 'total_accepted')
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_send_feedback
|
233
|
+
assert_command 'mollom.sendFeedback', :with => {:session_id => 1, :feedback => 'profanity'} do
|
234
|
+
@mollom.send_feedback :session_id => 1, :feedback => 'profanity'
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_detect_language
|
239
|
+
assert_command 'mollom.detectLanguage', :with => {:text => 'Dit is nederlands'}, :returns => [{"confidence"=>0.332, "language"=>"nl"}] do
|
240
|
+
assert_equal [{"confidence"=>0.332, "language"=>"nl"}], @mollom.language_for('Dit is nederlands')
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_api_compatability
|
245
|
+
assert @mollom.respond_to? :checkContent
|
246
|
+
assert @mollom.respond_to? :getImageCaptcha
|
247
|
+
assert @mollom.respond_to? :getAudioCaptcha
|
248
|
+
assert @mollom.respond_to? :checkCaptcha
|
249
|
+
assert @mollom.respond_to? :verifyKey
|
250
|
+
assert @mollom.respond_to? :getStatistics
|
251
|
+
assert @mollom.respond_to? :sendFeedback
|
252
|
+
assert @mollom.respond_to? :detectLanguage
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
def assert_command command, options = {}
|
257
|
+
expectation = Mollom.any_instance.expects(:send_command)
|
258
|
+
expectation.with do |*arguments|
|
259
|
+
arguments.first == command &&
|
260
|
+
(!options[:with] || options[:with] == arguments.last)
|
261
|
+
end
|
262
|
+
expectation.returns(options[:returns]) if options[:returns]
|
263
|
+
expectation.raises(options[:raises]) if options[:raises]
|
264
|
+
|
265
|
+
yield
|
266
|
+
end
|
267
|
+
|
268
|
+
def internal_server_error
|
269
|
+
XMLRPC::FaultException.new(1000, "Internal server error due to malformed request, or the hamster powering the server died...")
|
270
|
+
end
|
271
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bradleypriest-mollom
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.3
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jan De Poorter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-12 00:00:00 +12:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment.
|
18
|
+
email: mollom@openminds.be
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- lib/mollom.rb
|
31
|
+
- lib/mollom/api_compatibility.rb
|
32
|
+
- lib/mollom/content_response.rb
|
33
|
+
- mollom.gemspec
|
34
|
+
- pkg/mollom-0.1.1.gem
|
35
|
+
- test/content_response_test.rb
|
36
|
+
- test/mollom_test.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://mollom.rubyforge.com
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.5.2
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment.
|
65
|
+
test_files:
|
66
|
+
- test/content_response_test.rb
|
67
|
+
- test/mollom_test.rb
|