defensor 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in defensio.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Oleg Bovykin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Defensor
2
+
3
+ Unofficial gem for working with Defensio API 2.0
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'defensor'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Add initializer with api_key
16
+
17
+ Defensor.api_key = "YOUR_KEY_HERE"
18
+
19
+ ## Usage
20
+
21
+ Post document for spam chek:
22
+
23
+ d = Defensor.new(content: "lalalalalalal", type: :forum, platform: "my_awesome_app")
24
+ d.post_document
25
+ => [200, {"status"=>"success", "message"=>"", "api-version"=>"2.0", "signature"=>"1fd5c9de6a77f28256fba1", "allow"=>true, "spaminess"=>0.05, "classification"=>"legitimate", "profanity-match"=>false}]
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'lib' << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.verbose = false
9
+ end
10
+
11
+ task :default => :test
data/defensor.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'defensor'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "defensor"
8
+ spec.version = Defensor::VERSION
9
+ spec.authors = ["Oleg Bovykin"]
10
+ spec.email = ["oleg.bovykin@gmail.com"]
11
+ spec.description = %q{Unofficial Ruby library for Defensio 2.0}
12
+ spec.summary = %q{Unofficial Ruby library for Defensio 2.0}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "mocha"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "guard-rspec"
26
+
27
+ spec.add_dependency "json"
28
+ spec.add_dependency "facets"
29
+ spec.add_dependency "httparty"
30
+ end
@@ -0,0 +1,296 @@
1
+ class Module
2
+
3
+ # Creates a class-variable attribute that can
4
+ # be accessed both on an instance and class level.
5
+ #
6
+ # class CARExample
7
+ # @@a = 10
8
+ # cattr :a
9
+ # end
10
+ #
11
+ # CARExample.a #=> 10
12
+ # CARExample.new.a #=> 10
13
+ #
14
+ # NOTE: This method is not a common core extension and is not
15
+ # loaded automatically when using <code>require 'facets'</code>.
16
+ #
17
+ # CREDIT: David Heinemeier Hansson
18
+ #
19
+ # @uncommon
20
+ # require 'facets/module/cattr'
21
+ #
22
+ def cattr(*syms)
23
+ writers, readers = syms.flatten.partition{ |a| a.to_s =~ /=$/ }
24
+ writers = writers.map{ |e| e.to_s.chomp('=').to_sym }
25
+ ##readers.concat( writers ) # writers also get readers
26
+
27
+ cattr_reader(*readers)
28
+ cattr_writer(*writers)
29
+
30
+ return readers + writers
31
+ end
32
+
33
+ # Creates a class-variable attr_reader that can
34
+ # be accessed both on an instance and class level.
35
+ #
36
+ # class CARExample
37
+ # @@a = 10
38
+ # cattr_reader :a
39
+ # end
40
+ #
41
+ # CARExample.a #=> 10
42
+ # CARExample.new.a #=> 10
43
+ #
44
+ # NOTE: This method is not a common core extension and is not
45
+ # loaded automatically when using <code>require 'facets'</code>.
46
+ #
47
+ # CREDIT: David Heinemeier Hansson
48
+ #
49
+ # @uncommon
50
+ # require 'facets/module/cattr'
51
+ #
52
+ def cattr_reader(*syms)
53
+ syms.flatten.each do |sym|
54
+ module_eval(<<-EOS, __FILE__, __LINE__)
55
+ unless defined? @@#{sym}
56
+ @@#{sym} = nil
57
+ end
58
+
59
+ def self.#{sym}
60
+ @@#{sym}
61
+ end
62
+
63
+ def #{sym}
64
+ @@#{sym}
65
+ end
66
+ EOS
67
+ end
68
+ return syms
69
+ end
70
+
71
+ # Creates a class-variable attr_writer that can
72
+ # be accessed both on an instance and class level.
73
+ #
74
+ # class CAWExample
75
+ # cattr_writer :a
76
+ # def self.a
77
+ # @@a
78
+ # end
79
+ # end
80
+ #
81
+ # CAWExample.a = 10
82
+ # CAWExample.a #=> 10
83
+ # CAWExample.new.a = 29
84
+ # CAWExample.a #=> 29
85
+ #
86
+ # NOTE: This method is not a common core extension and is not
87
+ # loaded automatically when using <code>require 'facets'</code>.
88
+ #
89
+ # CREDIT: David Heinemeier Hansson
90
+ #
91
+ # @uncommon
92
+ # require 'facets/module/cattr'
93
+ #
94
+ def cattr_writer(*syms)
95
+ syms.flatten.each do |sym|
96
+ module_eval(<<-EOS, __FILE__, __LINE__)
97
+ unless defined? @@#{sym}
98
+ @@#{sym} = nil
99
+ end
100
+
101
+ def self.#{sym}=(obj)
102
+ @@#{sym} = obj
103
+ end
104
+
105
+ def #{sym}=(obj)
106
+ @@#{sym}=(obj)
107
+ end
108
+ EOS
109
+ end
110
+ return syms
111
+ end
112
+
113
+ # Creates a class-variable attr_accessor that can
114
+ # be accessed both on an instance and class level.
115
+ #
116
+ # class CAAExample
117
+ # cattr_accessor :a
118
+ # end
119
+ #
120
+ # CAAExample.a = 10
121
+ # CAAExample.a #=> 10
122
+ # mc = CAAExample.new
123
+ # mc.a #=> 10
124
+ #
125
+ # NOTE: This method is not a common core extension and is not
126
+ # loaded automatically when using <code>require 'facets'</code>.
127
+ #
128
+ # CREDIT: David Heinemeier Hansson
129
+ #
130
+ # @uncommon
131
+ # require 'facets/module/cattr'
132
+ #
133
+ def cattr_accessor(*syms)
134
+ cattr_reader(*syms) + cattr_writer(*syms)
135
+ end
136
+
137
+ # Creates a class-variable attribute that can
138
+ # be accessed both on an instance and class level.
139
+ #
140
+ # c = Class.new do
141
+ # mattr :a
142
+ # def initialize
143
+ # @@a = 10
144
+ # end
145
+ # end
146
+ #
147
+ # c.new.a #=> 10
148
+ # c.a #=> 10
149
+ #
150
+ # NOTE: The #mattr methods may not be as useful for modules as the #cattr
151
+ # methods are for classes, becuase class-level methods are not "inherited"
152
+ # across the metaclass for included modules.
153
+ #
154
+ # NOTE: This methiod is not a common core extension and is not
155
+ # loaded automatically when using <code>require 'facets'</code>.
156
+ #
157
+ # CREDIT: David Heinemeier Hansson
158
+ #
159
+ # @uncommon
160
+ # require 'facets/module/mattr'
161
+ #
162
+ def mattr(*syms)
163
+ writers, readers = syms.flatten.partition{ |a| a.to_s =~ /=$/ }
164
+ writers = writers.collect{ |e| e.to_s.chomp('=').to_sym }
165
+ ##readers.concat( writers ) # writers also get readers
166
+
167
+ mattr_writer( *writers )
168
+ mattr_reader( *readers )
169
+
170
+ return readers + writers
171
+ end
172
+
173
+ # Creates a class-variable attr_reader that can
174
+ # be accessed both on an instance and class level.
175
+ #
176
+ # c = Class.new do
177
+ # @@a = 10
178
+ # mattr_reader :a
179
+ # end
180
+ #
181
+ # c.a #=> 10
182
+ # c.new.a #=> 10
183
+ #
184
+ # NOTE: This methiod is not a common core extension and is not
185
+ # loaded automatically when using <code>require 'facets'</code>.
186
+ #
187
+ # CREDIT: David Heinemeier Hansson
188
+ #
189
+ # @uncommon
190
+ # require 'facets/module/mattr'
191
+ #
192
+ def mattr_reader( *syms )
193
+ syms.flatten.each do |sym|
194
+ module_eval(<<-EOS, __FILE__, __LINE__)
195
+ unless defined? @@#{sym}
196
+ @@#{sym} = nil
197
+ end
198
+
199
+ def self.#{sym}
200
+ @@#{sym}
201
+ end
202
+
203
+ def #{sym}
204
+ @@#{sym}
205
+ end
206
+ EOS
207
+ end
208
+ return syms
209
+ end
210
+
211
+ # Creates a class-variable attr_writer that can
212
+ # be accessed both on an instance and class level.
213
+ #
214
+ # c = Class.new do
215
+ # mattr_writer :a
216
+ # def self.a
217
+ # @@a
218
+ # end
219
+ # end
220
+ #
221
+ # c.a = 10
222
+ # c.a #=> 10
223
+ #
224
+ # c.new.a = 29
225
+ # c.a #=> 29
226
+ #
227
+ # NOTE: This methiod is not a common core extension and is not
228
+ # loaded automatically when using <code>require 'facets'</code>.
229
+ #
230
+ # CREDIT: David Heinemeier Hansson
231
+ #
232
+ # @uncommon
233
+ # require 'facets/module/mattr'
234
+ #
235
+ def mattr_writer(*syms)
236
+ syms.flatten.each do |sym|
237
+ module_eval(<<-EOS, __FILE__, __LINE__)
238
+ unless defined? @@#{sym}
239
+ @@#{sym} = nil
240
+ end
241
+
242
+ def self.#{sym}=(obj)
243
+ @@#{sym} = obj
244
+ end
245
+
246
+ def #{sym}=(obj)
247
+ @@#{sym}=(obj)
248
+ end
249
+ EOS
250
+ end
251
+ return syms
252
+ end
253
+
254
+ # Creates a class-variable attr_accessor that can
255
+ # be accessed both on an instance and class level.
256
+ #
257
+ # c = Class.new do
258
+ # mattr_accessor :a
259
+ # end
260
+ #
261
+ # c.a = 10
262
+ # c.a #=> 10
263
+ #
264
+ # x = c.new
265
+ # x.a #=> 10
266
+ #
267
+ # NOTE: This methiod is not a common core extension and is not
268
+ # loaded automatically when using <code>require 'facets'</code>.
269
+ #
270
+ # CREDIT: David Heinemeier Hansson
271
+ #
272
+ # @uncommon
273
+ # require 'facets/module/mattr'
274
+ #
275
+ def mattr_accessor(*syms)
276
+ mattr_reader(*syms) + mattr_writer(*syms)
277
+ end
278
+
279
+ end
280
+
281
+ # Consider the issue where a module's metaclass is not inherited.
282
+ #
283
+ # m = Module.new do
284
+ # @@a = 10
285
+ # mattr_reader :a
286
+ # end
287
+ #
288
+ # c = Class.new do
289
+ # include m
290
+ # end
291
+ #
292
+ # expect NoMethodError do
293
+ # c.a
294
+ # end
295
+ #
296
+ # Ideally this would work.
@@ -0,0 +1,3 @@
1
+ module Defensor::Version
2
+ VERSION = "0.1.0"
3
+ end
data/lib/defensor.rb ADDED
@@ -0,0 +1,163 @@
1
+
2
+ #
3
+ # Defensio-Ruby
4
+ # Written by the Defensio team at Websense, Inc.
5
+ #
6
+
7
+ require 'rubygems'
8
+ require 'httparty'
9
+ require 'uri'
10
+ require 'json'
11
+
12
+ class Defensor
13
+ require 'defensor/cattr'
14
+ require "defensor/version"
15
+ include Version
16
+
17
+ class NoApiKeyException < Exception; end
18
+ class NoContentException < Exception; end
19
+ class NoSignatureException < Exception; end
20
+
21
+ cattr_accessor 'api_key'
22
+ ALLOWED_OPTIONS = [:type, :platform, "author-email", "author-ip", :content, :signature]
23
+
24
+ # You shouldn't modify these values unless you really know what you are doing. And then again...
25
+ API_VERSION = 2.0
26
+ API_HOST = "http://api.defensio.com"
27
+
28
+ # You should't modify anything below this line.
29
+ LIB_VERSION = Defensor::VERSION
30
+ ROOT_NODE = "defensio-result"
31
+ FORMAT = :json
32
+ USER_AGENT = "Defensor #{LIB_VERSION}"
33
+ CLIENT = "Defensor | #{LIB_VERSION} | Oleg Bovykin | oleg.bovykin@gmail.com"
34
+ KEEP_ALIVE = false
35
+
36
+ attr_accessor :options, :signature
37
+
38
+ include HTTParty
39
+ format FORMAT
40
+ base_uri API_HOST
41
+
42
+ def self.respond(response)
43
+ [response.code, response[ROOT_NODE]]
44
+ end
45
+
46
+ # Get information about the api key
47
+ def self.get_user
48
+ respond get(api_path)
49
+ end
50
+
51
+ def self.api_path(action = nil, id = nil)
52
+ path = "/#{API_VERSION}/users/#{@@api_key}"
53
+ path += "/#{action}" if action
54
+ path += "/#{id}" if id
55
+ path += ".#{FORMAT}"
56
+ end
57
+
58
+ # Get basic statistics for the current user
59
+ # @return [Array] An array containing 2 values: the HTTP status code & a Hash with the values returned by Defensio
60
+ def self.get_basic_stats
61
+ respond get(api_path("basic-stats"))
62
+ end
63
+
64
+ # Get more exhaustive statistics for the current user
65
+ # @param [Hash] data The parameters to be sent to Defensio. Keys can either be Strings or Symbols
66
+ # @return [Array] An array containing 2 values: the HTTP status code & a Hash with the values returned by Defensio
67
+ def self.get_extended_stats(data)
68
+ result = get(api_path("extended-stats"), :query => data)
69
+ code = result.code
70
+ result = result[ROOT_NODE]
71
+
72
+ 0.upto(result["data"].size - 1) do |i|
73
+ result["data"][i]["date"] = Date.parse(result["data"][i]["date"])
74
+ end
75
+
76
+ [code, result]
77
+ end
78
+
79
+ # Filter a set of values based on a pre-defined dictionary
80
+ def self.post_profanity_filter(data)
81
+ respond post(api_path("profanity-filter"), :body => data)
82
+ end
83
+
84
+ def self.parse_body(str)
85
+ if FORMAT == :json
86
+ return JSON.parse(str)[ROOT_NODE]
87
+ else
88
+ raise(NotImplementedError, "This library doesn't support this format: #{FORMAT}")
89
+ end
90
+ end
91
+
92
+ # Takes the request object (Rails, Sinatra, Merb) of an async request callback and returns a hash
93
+ # containing the status of the document being analyzed.
94
+ # @param [ActionController::Request, Sinatra::Request, String] request The request object created after Defensio POSTed to your site, or a string representation of the POST data.
95
+ # @return [Hash] Status of the document
96
+ def self.handle_post_document_async_callback(request)
97
+ if request.is_a?(String)
98
+ data = request
99
+ elsif request.respond_to?(:body) && request.body.respond_to?(:read)
100
+ data = request.body.read
101
+ else
102
+ raise ArgumentError, "Unknown request type: #{request.class}"
103
+ end
104
+
105
+ Defensor.parse_body(data)
106
+ end
107
+
108
+ def initialize(*options)
109
+ check_key
110
+ @options = options[0].reject {|k, v| !(ALLOWED_OPTIONS.include? k)}
111
+ @signature = @options['signature'] if @options['signature']
112
+ end
113
+
114
+ def check_key
115
+ raise NoApiKeyException if @@api_key.nil? || @@api_key.empty?
116
+ end
117
+
118
+ def check_document
119
+ raise NoContentException if content.nil? || content.empty?
120
+ end
121
+
122
+ def content
123
+ @options[:content]
124
+ end
125
+
126
+ # Create and analyze a new document
127
+ # @param [Hash] data The parameters to be sent to Defensio. Keys can either be Strings or Symbols
128
+ # @return [Array] An array containing 2 values: the HTTP status code & a Hash with the values returned by Defensio
129
+ def post_document
130
+ check_document
131
+ response = Defensor.post(Defensor.api_path("documents"), :body => { :client => CLIENT }.merge(@options))
132
+ status = response[ROOT_NODE]["status"]
133
+ @signature = response[ROOT_NODE]["signature"] if status == "success"
134
+ Defensor.respond response
135
+ end
136
+
137
+ # Get the status of an existing document
138
+ # @param [String] signature The signature of the document to retrieve
139
+ # @return [Array] An array containing 2 values: the HTTP status code & a Hash with the values returned by Defensio
140
+ def get_document(signature=nil)
141
+ @signature ||= signature
142
+ if @signature
143
+ Defensor.respond Defensor.get(Defensor.api_path("documents", @signature))
144
+ else
145
+ raise NoSignatureException
146
+ end
147
+ end
148
+
149
+ # Modify the properties of an existing document
150
+ # @param [String] signature The signature of the document to modify
151
+ # @param [Hash] data The parameters to be sent to Defensio. Keys can either be Strings or Symbols
152
+ # @return [Array] An array containing 2 values: the HTTP status code & a Hash with the values returned by Defensio
153
+ def put_document(signature=nil, data)
154
+ @signature ||= signature
155
+ if @signature
156
+ Defensor.respond Defensor.put(Defensor.api_path("documents", @signature), :body => data)
157
+ else
158
+ raise NoSignatureException
159
+ end
160
+ end
161
+
162
+ end
163
+
@@ -0,0 +1,178 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Defensor do
6
+ before { Defensor.api_key = ENV['DEFENSIO_KEY'] }
7
+
8
+ context "initialize" do
9
+ let(:defensor_no_key) { Defensor.api_key = nil; Defensor.new({}) }
10
+ let(:defensor) { Defensor.api_key = "ABC"; Defensor.new({type: :forum, platform: :movable_type, nonrelevant: :abc}) }
11
+
12
+ it "Accepts input params with key" do
13
+ expect(defensor.options.keys).not_to include "nonrelevant"
14
+ end
15
+
16
+ it "Throws Exception if api_key not set" do
17
+ lambda { defensor_no_key }.should raise_exception(Defensor::NoApiKeyException)
18
+ end
19
+ end
20
+
21
+ context ".api_path" do
22
+
23
+ it "returns valid url with no options" do
24
+ expect(Defensor.api_path).to eq "/#{Defensor::API_VERSION}/users/#{Defensor.api_key}.json"
25
+ end
26
+
27
+ it "returns valid url with action" do
28
+ expect(Defensor.api_path("action")).to eq "/#{Defensor::API_VERSION}/users/#{Defensor.api_key}/action.json"
29
+ end
30
+
31
+ it "returns valid url with action and id" do
32
+ expect(Defensor.api_path("action", "id")).to eq "/#{Defensor::API_VERSION}/users/#{Defensor.api_key}/action/id.json"
33
+ end
34
+ end
35
+
36
+ if ENV['DEFENSIO_KEY']
37
+
38
+ context "real_requests" do
39
+ before { Defensor.api_key = ENV['DEFENSIO_KEY'] }
40
+
41
+ context ".get_user" do
42
+ let(:get_user) { Defensor.get_user }
43
+
44
+ it "returns valid response" do
45
+ status, body = get_user
46
+ expect(body.is_a? Hash).to eq true
47
+ expect(status).to eq 200
48
+ expect(body['status']).to eq "success"
49
+ end
50
+ end
51
+
52
+ context ".get_basic_stats" do
53
+ let(:stats) { Defensor.get_basic_stats }
54
+
55
+ it "returns valid result" do
56
+ status, body = stats
57
+ expect(body.is_a? Hash).to eq true
58
+ expect(status).to eq 200
59
+ expect(body['status']).to eq "success"
60
+ expect(body["unwanted"]["total"].is_a? Integer).to eq true
61
+ end
62
+ end
63
+
64
+ context ".get_extended_stats" do
65
+ let(:stats) { Defensor.get_extended_stats(:from => Date.new(2009, 9, 1), :to => Date.new(2009, 9, 3)) }
66
+
67
+ it "returns valid result" do
68
+ status, body = stats
69
+ expect(body.is_a? Hash).to eq true
70
+ expect(status).to eq 200
71
+ expect(body['data'].is_a? Array).to eq true
72
+ expect(body["data"][0]["date"].is_a? Date ).to eq true if body["data"].size > 0
73
+ end
74
+ end
75
+
76
+ context ".post_profanity_filter" do
77
+ let(:stats) { Defensor.post_profanity_filter("field1"=>"hello world", "other_field"=>"hello again") }
78
+
79
+ it "returns valid result" do
80
+ status, body = stats
81
+ expect(body.is_a? Hash).to eq true
82
+ expect(status).to eq 200
83
+ expect(body["filtered"].is_a? Hash).to eq true
84
+ expect(body["filtered"].keys).to include "field1"
85
+ expect(body["filtered"].keys).to include "other_field"
86
+ end
87
+ end
88
+
89
+ context ".parse_body" do
90
+ let(:body) { Defensor.parse_body '{"defensio-result":{"hello":"world"}}'}
91
+ let(:result) { {"hello" => "world"} }
92
+
93
+ it "returns valid result" do
94
+ expect(body).to eq result
95
+ end
96
+ end
97
+
98
+ context "#post_document" do
99
+ let(:defensor) { Defensor.new({type: :forum, platform: :movable_type, nonrelevant: :abc, content: "My test content for defensor"}) }
100
+ let(:response) { defensor.post_document }
101
+
102
+ it "puts document to defensio and sets signature" do
103
+ status, body = response
104
+ expect(defensor.signature).to eq body["signature"]
105
+ expect(status).to eq 200
106
+ end
107
+ end
108
+
109
+ context ".handle_post_document_async_callback__string" do
110
+ require 'ostruct'
111
+ let(:result) { { "defensio-result" =>
112
+ { "api-version" => Defensor::API_VERSION,
113
+ "status" => "success",
114
+ "message" => nil,
115
+ "signature" => "123456",
116
+ "allow" => false,
117
+ "classification" => "malicious",
118
+ "spaminess" => 0.95,
119
+ "profanity-match" => true }
120
+ } }
121
+ let(:request) { OpenStruct.new(:body => StringIO.new(result.to_json)) }
122
+
123
+ it "checks string" do
124
+ expect(Defensor.handle_post_document_async_callback(result.to_json).class).to eq Hash
125
+ end
126
+
127
+ it "checks object" do
128
+ result = Defensor.handle_post_document_async_callback(request)
129
+ expect(result.class).to eq Hash
130
+ expect(result["status"]).to eq "success"
131
+ end
132
+ end
133
+
134
+ context "integration" do
135
+ let(:defensor) { Defensor.api_key = ENV['DEFENSIO_KEY']; Defensor.new({:content => "This is a simple test", :platform => "
136
+ my_test_platform", :type => "comment"}) }
137
+ let(:post) { defensor.post_document }
138
+
139
+ it "test post get put" do
140
+ status, body = post
141
+ expect(body.is_a? Hash).to eq true
142
+ expect(status).to eq 200
143
+ expect(body["status"]).to eq "success"
144
+ expect(defensor.signature).to eq body["signature"]
145
+
146
+ # Keep some variables around
147
+ original_allow_result = body["allow"]
148
+
149
+ sleep 0.5
150
+
151
+ # GET
152
+ status, body = defensor.get_document
153
+ expect(body.is_a? Hash).to eq true
154
+ expect(status).to eq 200
155
+ expect(body["status"]).to eq "success"
156
+ expect(defensor.signature).to eq body["signature"]
157
+
158
+ # PUT
159
+ status, body = defensor.put_document(:allow => !original_allow_result)
160
+ expect(body.is_a? Hash).to eq true
161
+ expect(status).to eq 200
162
+ expect(body["status"]).to eq "success"
163
+ expect(defensor.signature).to eq body["signature"]
164
+ expect(body["allow"]).to eq !original_allow_result
165
+
166
+ status, body = defensor.put_document(:allow => original_allow_result)
167
+ expect(body.is_a? Hash).to eq true
168
+ expect(status).to eq 200
169
+ expect(body["status"]).to eq "success"
170
+ expect(defensor.signature).to eq body["signature"]
171
+ expect(body["allow"]).to eq original_allow_result
172
+ end
173
+ end
174
+
175
+ end # context "real_requests"
176
+ end # if ENV['DEFENSIO_KEY']
177
+
178
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'defensor'
3
+
4
+ RSpec.configure do |c|
5
+ c.mock_with :rspec
6
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: defensor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.11.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oleg Bovykin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mocha
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: guard-rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: json
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: facets
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: httparty
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: Unofficial Ruby library for Defensio 2.0
143
+ email:
144
+ - oleg.bovykin@gmail.com
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - .gitignore
150
+ - .rspec
151
+ - Gemfile
152
+ - Guardfile
153
+ - LICENSE.txt
154
+ - README.md
155
+ - Rakefile
156
+ - defensor.gemspec
157
+ - lib/defensor.rb
158
+ - lib/defensor/cattr.rb
159
+ - lib/defensor/version.rb
160
+ - spec/models/defensor_spec.rb
161
+ - spec/spec_helper.rb
162
+ homepage: ''
163
+ licenses:
164
+ - MIT
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ none: false
177
+ requirements:
178
+ - - ! '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubyforge_project:
183
+ rubygems_version: 1.8.25
184
+ signing_key:
185
+ specification_version: 3
186
+ summary: Unofficial Ruby library for Defensio 2.0
187
+ test_files:
188
+ - spec/models/defensor_spec.rb
189
+ - spec/spec_helper.rb