mollom 0.1 → 0.1.1
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/README +22 -10
- data/lib/mollom.rb +22 -8
- data/test/content_response_test.rb +33 -0
- data/test/mollom_test.rb +136 -0
- metadata +6 -5
data/README
CHANGED
@@ -1,25 +1,37 @@
|
|
1
1
|
== Mollom
|
2
2
|
|
3
|
-
This is a Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality
|
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
|
4
12
|
|
5
13
|
== Usage
|
6
14
|
|
7
|
-
After you have requested a public/private
|
15
|
+
After you have requested a public/private key-pair from Mollom (on http://www.mollom.com), you can start using this class.
|
8
16
|
|
9
|
-
require '
|
17
|
+
require 'rubygems'
|
18
|
+
require 'mollom'
|
10
19
|
|
11
|
-
m = Mollom.new(:private_key => '
|
20
|
+
m = Mollom.new(:private_key => 'your-private-key', :public_key => 'your-public-key')
|
12
21
|
|
13
22
|
content = m.check_content(:post_title => 'Mollem is an open API',
|
14
|
-
:post_body => "
|
23
|
+
:post_body => "Lorem Ipsum dolor...",
|
15
24
|
:author_name => 'Jan De Poorter',
|
16
25
|
:author_url => 'http://blog.defv.be')
|
17
|
-
if content.
|
18
|
-
|
19
|
-
|
20
|
-
|
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)
|
21
33
|
else
|
22
34
|
puts "The post is perfect! No spam!"
|
23
35
|
end
|
24
36
|
|
25
|
-
Copyright (c) 2008 Jan De Poorter - Openminds BVBA, released under the MIT license
|
37
|
+
Copyright (c) 2008 Jan De Poorter - Openminds BVBA, released under the MIT license
|
data/lib/mollom.rb
CHANGED
@@ -2,6 +2,9 @@ require 'xmlrpc/client'
|
|
2
2
|
require 'openssl'
|
3
3
|
require 'base64'
|
4
4
|
|
5
|
+
# Mollom API requires this to change, but this gives a warning!
|
6
|
+
# XMLRPC::Client::USER_AGENT = "Ruby Mollom/0.1"
|
7
|
+
|
5
8
|
class Mollom
|
6
9
|
API_VERSION = '1.0'
|
7
10
|
module Errors
|
@@ -116,26 +119,36 @@ class Mollom
|
|
116
119
|
def send_command(command, data = {})
|
117
120
|
server_list.each do |server|
|
118
121
|
begin
|
119
|
-
return XMLRPC::Client.new(server, "/#{API_VERSION}").call(command, data.merge(authentication_hash))
|
122
|
+
return XMLRPC::Client.new(server[:ip], "/#{API_VERSION}").call(command, data.merge(authentication_hash))
|
123
|
+
# TODO: Rescue more stuff (Connection Timeout and such)
|
120
124
|
rescue XMLRPC::FaultException => error
|
121
125
|
case error.faultCode
|
122
126
|
when Errors::Standard
|
123
127
|
raise Error.new(error.faultString)
|
124
128
|
when Errors::Refresh
|
125
|
-
#
|
129
|
+
# we take this one out of our loop
|
130
|
+
raise
|
126
131
|
when Errors::Redirect
|
127
132
|
next
|
128
133
|
else
|
129
|
-
|
134
|
+
next
|
130
135
|
end
|
131
136
|
end
|
132
137
|
end
|
138
|
+
raise Mollom::NoAvailableServers
|
139
|
+
rescue XMLRPC::FaultException
|
140
|
+
# We know it is Errors::Refresh
|
141
|
+
server_list(true)
|
142
|
+
retry
|
133
143
|
end
|
134
144
|
|
135
145
|
# Gets a list of servers from Mollom
|
136
|
-
def server_list
|
137
|
-
|
138
|
-
@server_list ||= XMLRPC::Client.new("xmlrpc.mollom.com", "/#{API_VERSION}").call('mollom.getServerList', authentication_hash).collect
|
146
|
+
def server_list refresh = false
|
147
|
+
@server_list = nil if refresh
|
148
|
+
@server_list ||= XMLRPC::Client.new("xmlrpc.mollom.com", "/#{API_VERSION}").call('mollom.getServerList', authentication_hash).collect do |server|
|
149
|
+
proto, ip = server.split('://')
|
150
|
+
{:proto => proto, :ip => ip}
|
151
|
+
end
|
139
152
|
end
|
140
153
|
|
141
154
|
# Creates a HMAC-SHA1 Hash with the current timestamp, and your private key.
|
@@ -143,8 +156,8 @@ class Mollom
|
|
143
156
|
now = Time.now.gmtime.strftime('%Y-%m-%dT%H:%M:%S.000+0000')
|
144
157
|
|
145
158
|
hash = Base64.encode64(
|
146
|
-
|
147
|
-
)
|
159
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @private_key, now)
|
160
|
+
).chomp
|
148
161
|
|
149
162
|
return :public_key=> @public_key, :time => now, :hash => hash
|
150
163
|
end
|
@@ -196,4 +209,5 @@ class Mollom
|
|
196
209
|
end
|
197
210
|
|
198
211
|
class Error < StandardError; end
|
212
|
+
class NoAvailableServers < Error; end
|
199
213
|
end
|
@@ -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' => 3, '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' => 2, '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,136 @@
|
|
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.stubs(:now).returns(stub(:gmtime => time))
|
28
|
+
hash = @mollom.authentication_hash
|
29
|
+
assert_equal("24qAgAC1v1U+5NbKyrQSp/XKWAI=", hash[:hash])
|
30
|
+
assert_equal('yyyyyyyyy', hash[:public_key])
|
31
|
+
assert_equal('2008-04-01T13:54:26.000+0000', hash[:time])
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_server_list
|
35
|
+
xml_rpc = mock
|
36
|
+
xml_rpc.expects(:call).with('mollom.getServerList', is_a(Hash)).returns(['http://172.16.0.1', 'http://172.16.0.2', 'https://172.16.0.2'])
|
37
|
+
XMLRPC::Client.stubs(:new).with('xmlrpc.mollom.com', '/1.0').returns(xml_rpc)
|
38
|
+
|
39
|
+
assert_equal [{:ip => '172.16.0.1', :proto => 'http'}, {:ip => '172.16.0.2', :proto => 'http'}, {:ip => '172.16.0.2', :proto => 'https'}], @mollom.server_list
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_server_list_force_reload
|
43
|
+
xml_rpc = mock
|
44
|
+
xml_rpc.expects(:call).times(2).with('mollom.getServerList', is_a(Hash)).returns(['http://172.16.0.1', 'http://172.16.0.2', 'https://172.16.0.2'])
|
45
|
+
XMLRPC::Client.stubs(:new).with('xmlrpc.mollom.com', '/1.0').returns(xml_rpc)
|
46
|
+
|
47
|
+
@mollom.server_list
|
48
|
+
@mollom.server_list
|
49
|
+
@mollom.server_list(true)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_send_command_with_good_server
|
53
|
+
Mollom.any_instance.stubs(:server_list).returns([{:ip => '172.16.0.1', :proto => 'http'}])
|
54
|
+
xml_rpc = mock
|
55
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
56
|
+
XMLRPC::Client.stubs(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
57
|
+
|
58
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def test_send_command_with_bad_server
|
63
|
+
Mollom.any_instance.stubs(:server_list).returns([{:ip => '172.16.0.1', :proto => 'http'}, {:ip => '172.16.0.2', :proto => 'http'}])
|
64
|
+
xml_rpc = mock
|
65
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1200, "Redirect"))
|
66
|
+
xml_rpc2 = mock
|
67
|
+
xml_rpc2.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo'))
|
68
|
+
|
69
|
+
XMLRPC::Client.stubs(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
70
|
+
XMLRPC::Client.stubs(:new).with('172.16.0.2', '/1.0').returns(xml_rpc2)
|
71
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_send_command_with_reload_exception
|
75
|
+
# TODO: Test this
|
76
|
+
@mollom.send_command('mollom.testMessage', {:options => 'foo'})
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_send_command_with_bad_command
|
80
|
+
Mollom.any_instance.stubs(:server_list).returns([{:ip => '172.16.0.1', :proto => 'http'}])
|
81
|
+
xml_rpc = mock
|
82
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1000, "Fault String"))
|
83
|
+
XMLRPC::Client.stubs(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
84
|
+
|
85
|
+
assert_raise(Mollom::Error) { @mollom.send_command('mollom.testMessage', {:options => 'foo'}) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_send_command_with_bad_server_and_no_more_available
|
89
|
+
Mollom.any_instance.stubs(:server_list).returns([{:ip => '172.16.0.1', :proto => 'http'}])
|
90
|
+
xml_rpc = mock
|
91
|
+
xml_rpc.expects(:call).with('mollom.testMessage', has_entry(:options => 'foo')).raises(XMLRPC::FaultException.new(1200, "Redirect"))
|
92
|
+
|
93
|
+
XMLRPC::Client.stubs(:new).with('172.16.0.1', '/1.0').returns(xml_rpc)
|
94
|
+
|
95
|
+
assert_raise(Mollom::NoAvailableServers) { @mollom.send_command('mollom.testMessage', {:options => 'foo'}) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_check_content
|
99
|
+
Mollom.any_instance.expects(:send_command).with('mollom.checkContent', :author_ip => '172.16.0.1', :post_body => 'Lorem Ipsum').returns("spam" => 1, "quality" => 0.40, "session_id" => 1)
|
100
|
+
cr = @mollom.check_content(:author_ip => '172.16.0.1', :post_body => 'Lorem Ipsum')
|
101
|
+
assert cr.ham?
|
102
|
+
assert_equal 1, cr.session_id
|
103
|
+
assert_equal 0.40, cr.quality
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_image_captcha
|
107
|
+
Mollom.any_instance.expects(:send_command).with('mollom.getImageCaptcha', :author_ip => '172.16.0.1').returns('url' => 'http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.png', 'session_id' => 'a9616e6b4cd6a81ecdd509fa624d895d')
|
108
|
+
@mollom.image_captcha(:author_ip => '172.16.0.1')
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_audio_captcha
|
112
|
+
Mollom.any_instance.expects(:send_command).with('mollom.getAudioCaptcha', :author_ip => '172.16.0.1').returns('url' => 'http://xmlrpc1.mollom.com:80/a9616e6b4cd6a81ecdd509fa624d895d.mp3', 'session_id' => 'a9616e6b4cd6a81ecdd509fa624d895d')
|
113
|
+
@mollom.audio_captcha(:author_ip => '172.16.0.1')
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_valid_captcha
|
117
|
+
Mollom.any_instance.expects(:send_command).with('mollom.checkCaptcha', :session_id => 'a9616e6b4cd6a81ecdd509fa624d895d', :solution => 'foo').returns(true)
|
118
|
+
@mollom.valid_captcha?(:session_id => 'a9616e6b4cd6a81ecdd509fa624d895d', :solution => 'foo')
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_key_ok
|
122
|
+
Mollom.any_instance.expects(:send_command).with('mollom.verifyKey').returns(true)
|
123
|
+
@mollom.key_ok?
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_statistics
|
127
|
+
Mollom.any_instance.expects(:send_command).with('mollom.getStatistics', :type => 'total_accepted').returns(123)
|
128
|
+
@mollom.statistics(:type => 'total_accepted')
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_send_feedback
|
132
|
+
Mollom.any_instance.expects(:send_command).with('mollom.sendFeedback', :session_id => 1, :feedback => 'profanity')
|
133
|
+
@mollom.send_feedback :session_id => 1, :feedback => 'profanity'
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mollom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan De Poorter
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-04-
|
12
|
+
date: 2008-04-04 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -45,10 +45,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
45
|
version:
|
46
46
|
requirements: []
|
47
47
|
|
48
|
-
rubyforge_project:
|
48
|
+
rubyforge_project: mollom
|
49
49
|
rubygems_version: 1.0.1
|
50
50
|
signing_key:
|
51
51
|
specification_version: 2
|
52
52
|
summary: Ruby class for easy interfacing with the mollom.com open API for spam detection and content quality assesment.
|
53
|
-
test_files:
|
54
|
-
|
53
|
+
test_files:
|
54
|
+
- test/content_response_test.rb
|
55
|
+
- test/mollom_test.rb
|