bradleypriest-mollom 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|