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 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
@@ -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