crowdflower-rtfm 0.0.2
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/.document +5 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +39 -0
- data/LICENSE.txt +20 -0
- data/README.md +45 -0
- data/Rakefile +35 -0
- data/VERSION +1 -0
- data/crowdflower-rtfm.gemspec +73 -0
- data/examples/Gemfile +4 -0
- data/examples/README.md +10 -0
- data/examples/config.ru +2 -0
- data/examples/webhook.rb +23 -0
- data/examples/webhook_public.pem +9 -0
- data/lib/crowdflower-rtfm.rb +135 -0
- data/test/helper.rb +45 -0
- data/test/test_rtfm.rb +153 -0
- metadata +144 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "rest-client"
|
6
|
+
gem "multi_json"
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "minitest", ">= 0"
|
12
|
+
gem "bundler", "~> 1.0.0"
|
13
|
+
gem "jeweler", "~> 1.8.3"
|
14
|
+
gem "simplecov", ">= 0"
|
15
|
+
gem "webmock", ">= 0"
|
16
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.2.7)
|
5
|
+
crack (0.3.1)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.8.3)
|
8
|
+
bundler (~> 1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rake
|
11
|
+
rdoc
|
12
|
+
json (1.7.0)
|
13
|
+
mime-types (1.18)
|
14
|
+
minitest (2.12.1)
|
15
|
+
multi_json (1.3.4)
|
16
|
+
rake (0.9.2.2)
|
17
|
+
rdoc (3.12)
|
18
|
+
json (~> 1.4)
|
19
|
+
rest-client (1.6.7)
|
20
|
+
mime-types (>= 1.16)
|
21
|
+
simplecov (0.6.2)
|
22
|
+
multi_json (~> 1.3)
|
23
|
+
simplecov-html (~> 0.5.3)
|
24
|
+
simplecov-html (0.5.3)
|
25
|
+
webmock (1.8.6)
|
26
|
+
addressable (>= 2.2.7)
|
27
|
+
crack (>= 0.1.7)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
bundler (~> 1.0.0)
|
34
|
+
jeweler (~> 1.8.3)
|
35
|
+
minitest
|
36
|
+
multi_json
|
37
|
+
rest-client
|
38
|
+
simplecov
|
39
|
+
webmock
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 CrowdFlower
|
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.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# RTFM - Real Time Foto Moderator
|
2
|
+
|
3
|
+
Real Time Foto Moderator (RTFM) is Crowdsourced Image Moderation, learn more at http://crowdflower.com/rtfm. This gem is a simple wrapper for interacting with the API. Keep your app clean!
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```shell
|
8
|
+
gem install crowdflower-rtfm
|
9
|
+
```
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'rubygems'
|
13
|
+
require 'crowdflower-rtfm'
|
14
|
+
|
15
|
+
RTFM.api_key = "a1b2c3d4e5f6g7h8i9j0..."
|
16
|
+
#moderate_image accepts an optional metadata hash
|
17
|
+
res = RTFM.moderate_image("http://mysite.com/images/moderateme.jpg", {:id => 123})
|
18
|
+
RTFM.retrieve_image(res["image"]["id"])
|
19
|
+
```
|
20
|
+
|
21
|
+
## Exceptions
|
22
|
+
|
23
|
+
All exceptions thrown by the gem itself inherit from `RTFM::Error`. Below are the possible exceptions:
|
24
|
+
|
25
|
+
* RateLimitError - (rate limit exceeded)
|
26
|
+
* PaymentError - (account is out of money)
|
27
|
+
* AccountError - (your account is not authorized for this service)
|
28
|
+
* AuthenticationError - (your API key is invalid)
|
29
|
+
* InvalidRequestError - (one of your parameters is invalid, usually url)
|
30
|
+
* APIError - (a non 200 response code was returned, see the docs)
|
31
|
+
* APIConnectionError - (a network error occured)
|
32
|
+
|
33
|
+
## Webhook example
|
34
|
+
|
35
|
+
We've also included an example Sinatra server to consume webhooks from RTFM. You can find it at https://github.com/dolores/rtfm-ruby/tree/master/examples
|
36
|
+
|
37
|
+
# Acknowledgements
|
38
|
+
|
39
|
+
The implementation of this wrapper was inspired heavily by Stripes Ruby implementation (https://github.com/stripe/stripe-ruby). Thanks to Ross Boucher & Greg Brockman for bending RestClient to their will.
|
40
|
+
|
41
|
+
# Copyright
|
42
|
+
|
43
|
+
Copyright (c) 2012 CrowdFlower. See LICENSE.txt for
|
44
|
+
further details.
|
45
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "crowdflower-rtfm"
|
18
|
+
gem.homepage = "http://dolores.github.com/rtfm-api"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Simple Ruby wrapper for the RTFM API}
|
21
|
+
gem.description = %Q{Real Time Foto Moderator (RTFM) is Crowdsourced Image Moderation. Keep your app clean!}
|
22
|
+
gem.email = "vanpelt@crowdflower.com"
|
23
|
+
gem.authors = ["Chris Van Pelt"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "crowdflower-rtfm"
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Chris Van Pelt"]
|
12
|
+
s.date = "2012-05-07"
|
13
|
+
s.description = "Real Time Foto Moderator (RTFM) is Crowdsourced Image Moderation. Keep your app clean!"
|
14
|
+
s.email = "vanpelt@crowdflower.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"crowdflower-rtfm.gemspec",
|
28
|
+
"examples/Gemfile",
|
29
|
+
"examples/README.md",
|
30
|
+
"examples/config.ru",
|
31
|
+
"examples/webhook.rb",
|
32
|
+
"examples/webhook_public.pem",
|
33
|
+
"lib/crowdflower-rtfm.rb",
|
34
|
+
"test/helper.rb",
|
35
|
+
"test/test_rtfm.rb"
|
36
|
+
]
|
37
|
+
s.homepage = "http://dolores.github.com/rtfm-api"
|
38
|
+
s.licenses = ["MIT"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = "1.8.10"
|
41
|
+
s.summary = "Simple Ruby wrapper for the RTFM API"
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_runtime_dependency(%q<rest-client>, [">= 0"])
|
48
|
+
s.add_runtime_dependency(%q<multi_json>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
52
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<rest-client>, [">= 0"])
|
56
|
+
s.add_dependency(%q<multi_json>, [">= 0"])
|
57
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
58
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
59
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
60
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
61
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<rest-client>, [">= 0"])
|
65
|
+
s.add_dependency(%q<multi_json>, [">= 0"])
|
66
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
67
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
69
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
70
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
data/examples/Gemfile
ADDED
data/examples/README.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#Sample webhook consumer
|
2
|
+
|
3
|
+
You can take the contents of this folder and put them into a new git repo. This will allows you to push the repo to heroku and have a functioning webhook.
|
4
|
+
|
5
|
+
##Debugging
|
6
|
+
|
7
|
+
```bash
|
8
|
+
heroku config:add LOG_LEVEL=DEBUG
|
9
|
+
heroku logs -t
|
10
|
+
```
|
data/examples/config.ru
ADDED
data/examples/webhook.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'multi_json'
|
4
|
+
require 'openssl'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
PKey = OpenSSL::PKey::RSA.new(File.read(File.join(File.dirname(__FILE__), "webhook_public.pem")))
|
8
|
+
|
9
|
+
post "/rtfm_webhook" do
|
10
|
+
signature = env['X-CrowdFlower-Signature']
|
11
|
+
body = request.body.read
|
12
|
+
if(@public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), body))
|
13
|
+
payload = MultiJson.load(body)
|
14
|
+
#Do something meaningful with the payload here
|
15
|
+
logger.debug "SUCCESS"
|
16
|
+
logger.debug payload
|
17
|
+
200
|
18
|
+
else
|
19
|
+
logger.debug "FAILURE #{signature}"
|
20
|
+
logger.debug body
|
21
|
+
401
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0I0daumhUqIn4nIFcWEb
|
3
|
+
bTtL7F9a0d/a5d09/bnHNZcxOALjHir8iBKe3nSLRaKZDWd+MmxseD90dEbRtsvM
|
4
|
+
9lZ5bfFnXga43IAonnTZmLbqMsUNMByLLrfthlkUsU9arRJxEWK5I4eCON2JVm9E
|
5
|
+
ruQLaNi8RqitHwGvsfiOQm2gchoMj8kOyrVvdoUldSu3VZN7AbJ+mrsmFwEfQd5h
|
6
|
+
LzqLfHBCx7YlnWVFoNC3mOzxqpzJKdL+t1mXi7ewZSsCZzEL1LdeqJ3UTpSrNIRA
|
7
|
+
DU1UB+Pi7aybUIIDWC04jmRAPRiMSg87zK9bL+oXM0QWT7Zi8/EF76ZdeIaH2YrL
|
8
|
+
cQIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'openssl'
|
3
|
+
require 'rest_client'
|
4
|
+
require 'multi_json'
|
5
|
+
|
6
|
+
module RTFM
|
7
|
+
VERSION = File.read(File.join(File.dirname(__FILE__),"..","VERSION"))
|
8
|
+
@@api_key = nil
|
9
|
+
@@api_base = "https://rtfm.crowdflower.com/v1"
|
10
|
+
|
11
|
+
def self.api_key=(api_key); @@api_key = api_key; end
|
12
|
+
def self.api_key; @@api_key; end
|
13
|
+
def self.api_base=(api_base); @@api_base = api_base; end
|
14
|
+
def self.api_base; @@api_base; end
|
15
|
+
def self.api_url(url=''); @@api_base + url; end
|
16
|
+
|
17
|
+
def self.moderate_image(url, metadata = nil)
|
18
|
+
params = {:url => url}
|
19
|
+
params.merge!(:metadata => metadata) if metadata
|
20
|
+
request("/images", :post, params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.retrieve_image(id)
|
24
|
+
request("/images/#{id}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.request(url, method = :get, params = nil, api_key = nil, headers = {})
|
28
|
+
api_key ||= @@api_key
|
29
|
+
raise AuthenticationError.new("Please provide an API key (RTFM.api_key = <API-KEY>, your API key can be found by clicking \"APISettings\" @ http://crowdflower.com/rtfm)") unless api_key
|
30
|
+
|
31
|
+
#RestClient appends get parameters by looking for params in headers... lame
|
32
|
+
if method == :get && params
|
33
|
+
headers.merge!(:params => params)
|
34
|
+
params = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
opts = {
|
38
|
+
:user => api_key,
|
39
|
+
:timeout => 30,
|
40
|
+
:url => api_url(url),
|
41
|
+
:method => method,
|
42
|
+
:headers => {
|
43
|
+
:user_agent => "RTFM/v1 RubyGem/#{VERSION}",
|
44
|
+
:accept => "application/json"
|
45
|
+
}.merge(headers),
|
46
|
+
:payload => params
|
47
|
+
}
|
48
|
+
|
49
|
+
response = RestClient::Request.execute(opts)
|
50
|
+
MultiJson.load(response.body, :symbolize_keys => true)
|
51
|
+
rescue SocketError => e
|
52
|
+
self.handle_restclient_error(e)
|
53
|
+
rescue RestClient::ExceptionWithResponse => e
|
54
|
+
rcode = e.http_code
|
55
|
+
rbody = e.http_body
|
56
|
+
if rcode && rbody
|
57
|
+
self.handle_api_error(rcode, rbody)
|
58
|
+
else
|
59
|
+
self.handle_restclient_error(e)
|
60
|
+
end
|
61
|
+
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
62
|
+
self.handle_restclient_error(e)
|
63
|
+
rescue MultiJson::DecodeError
|
64
|
+
raise APIError.new("Invalid response body: #{response.body.inspect}. (HTTP response code of #{response.code})", response.code, response.body)
|
65
|
+
end
|
66
|
+
|
67
|
+
class Error < StandardError
|
68
|
+
attr_reader :message
|
69
|
+
attr_reader :http_status
|
70
|
+
attr_reader :http_body
|
71
|
+
attr_reader :json_body
|
72
|
+
|
73
|
+
def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
|
74
|
+
@message = message
|
75
|
+
@http_status = http_status
|
76
|
+
@http_body = http_body
|
77
|
+
@json_body = json_body
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_s
|
81
|
+
status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
|
82
|
+
"#{status_string}#{@message}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class RateLimitError < Error; end
|
87
|
+
class APIError < Error; end
|
88
|
+
class PaymentError < Error; end
|
89
|
+
class AccountError < Error; end
|
90
|
+
class AuthenticationError < Error; end
|
91
|
+
class InvalidRequestError < Error; end
|
92
|
+
class APIConnectionError < Error; end
|
93
|
+
|
94
|
+
def self.error(klass = Error, error, rcode, rbody, error_obj); klass.new(error, rcode, rbody, error_obj); end
|
95
|
+
|
96
|
+
def self.handle_api_error(rcode, rbody)
|
97
|
+
begin
|
98
|
+
error_obj = MultiJson.load(rbody, :symbolize_keys => true)
|
99
|
+
error = error_obj[:error] or raise Error.new # escape from parsing
|
100
|
+
rescue MultiJson::DecodeError, Error
|
101
|
+
raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
|
102
|
+
end
|
103
|
+
|
104
|
+
case rcode
|
105
|
+
when 503
|
106
|
+
raise error(RateLimitError, error, rcode, rbody, error_obj)
|
107
|
+
when 400, 404 then
|
108
|
+
raise error(InvalidRequestError, error, rcode, rbody, error_obj)
|
109
|
+
when 401
|
110
|
+
raise error(AuthenticationError, error, rcode, rbody, error_obj)
|
111
|
+
when 402
|
112
|
+
raise error(PaymentError, error, rcode, rbody, error_obj)
|
113
|
+
when 403
|
114
|
+
raise error(AccountError, error, rcode, rbody, error_obj)
|
115
|
+
else
|
116
|
+
raise error(APIError, error, rcode, rbody, error_obj)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.handle_restclient_error(e)
|
121
|
+
case e
|
122
|
+
when RestClient::ServerBrokeConnection, RestClient::RequestFailed
|
123
|
+
message = "Could not connect to RTFM (#{@@api_base}). Please check your internet connection and try again. If this problem persists, you should check RTFM's service status at https://twitter.com/cfstatus, or let us know at rtfm@crowdflower.com."
|
124
|
+
when RestClient::SSLCertificateNotVerified
|
125
|
+
message = "Could not verify RTFM's SSL certificate. Please make sure that your network is not intercepting certificates. If this problem persists, let us know at rtfm@crowdflower.com."
|
126
|
+
when SocketError
|
127
|
+
message = "Unexpected error communicating when trying to connect to RTFM. HINT: You may be seeing this message because your DNS is not working. To check, try running 'host stripe.com' from the command line."
|
128
|
+
else
|
129
|
+
message = "Unexpected error communicating with RTFM. If this problem persists, let us know at rtfm@crowdflower.com"
|
130
|
+
end
|
131
|
+
message += "\n\n(Network error: #{e.message})"
|
132
|
+
raise APIConnectionError.new(message)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
require 'minitest/spec'
|
14
|
+
require 'minitest/autorun'
|
15
|
+
require 'webmock/minitest'
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
18
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
19
|
+
require 'rtfm'
|
20
|
+
|
21
|
+
def moderate_success_body(url, metadata = {})
|
22
|
+
MultiJson.dump(
|
23
|
+
"image" => {
|
24
|
+
"id" => 1,
|
25
|
+
"url" => url,
|
26
|
+
"metadata" => metadata
|
27
|
+
}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def retrieve_success_body(id)
|
32
|
+
MultiJson.dump(
|
33
|
+
"image" => {
|
34
|
+
"id" => id,
|
35
|
+
"url" => "http://vanpe.lt/fake.jpg",
|
36
|
+
"score" => 0.6,
|
37
|
+
"rating" => "accepted",
|
38
|
+
"state" => "completed",
|
39
|
+
"metadata" => {}
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
class MiniTest::Spec::TestCase
|
45
|
+
end
|
data/test/test_rtfm.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe RTFM do
|
4
|
+
before do
|
5
|
+
@url = "http://vanpe.lt/awesome.jpg"
|
6
|
+
RTFM.api_key = "1234"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "makes successful requests" do
|
10
|
+
it "moderates without metadata" do
|
11
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").with(
|
12
|
+
:body => /awesome/,
|
13
|
+
:headers => {'User-Agent'=>"RTFM/v1 RubyGem/#{RTFM::VERSION}"}
|
14
|
+
).to_return(:status => 200, :body => moderate_success_body(@url))
|
15
|
+
res = RTFM.moderate_image(@url)
|
16
|
+
res[:image][:id].must_equal(1)
|
17
|
+
res[:image][:metadata].must_equal({})
|
18
|
+
end
|
19
|
+
|
20
|
+
it "moderates with metadata" do
|
21
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").with(
|
22
|
+
:body => /metadata\[foo\]=123/
|
23
|
+
).to_return(:status => 200, :body => moderate_success_body(@url, {:foo => 123}))
|
24
|
+
res = RTFM.moderate_image(@url, {:foo => 123})
|
25
|
+
res[:image][:metadata].must_equal({:foo => 123})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "retrieves analysis" do
|
29
|
+
stub_request(:get, "https://1234:@rtfm.crowdflower.com/v1/images/1").to_return(:status => 200, :body => retrieve_success_body(1))
|
30
|
+
res = RTFM.retrieve_image(1)
|
31
|
+
res[:image][:url].must_equal("http://vanpe.lt/fake.jpg")
|
32
|
+
res[:image][:id].must_equal(1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "handles network errors" do
|
37
|
+
it "catches ERRNO" do
|
38
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_raise(Errno::ECONNREFUSED)
|
39
|
+
error = lambda {
|
40
|
+
RTFM.moderate_image(@url)
|
41
|
+
}.must_raise(RTFM::APIConnectionError)
|
42
|
+
error.to_s.must_match /Connection refused/
|
43
|
+
end
|
44
|
+
|
45
|
+
it "catches timeout" do
|
46
|
+
#The struct is a hack to prevent an infinite loop in RestClient
|
47
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_raise(RestClient::RequestFailed.new(OpenStruct.new(:net_http_res => nil)))
|
48
|
+
error = lambda {
|
49
|
+
RTFM.moderate_image(@url)
|
50
|
+
}.must_raise(RTFM::APIConnectionError)
|
51
|
+
error.to_s.must_match /Could not connect/
|
52
|
+
end
|
53
|
+
|
54
|
+
it "catches SocketError" do
|
55
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_raise(SocketError)
|
56
|
+
error = lambda {
|
57
|
+
RTFM.moderate_image(@url)
|
58
|
+
}.must_raise(RTFM::APIConnectionError)
|
59
|
+
error.to_s.must_match /Network error/
|
60
|
+
end
|
61
|
+
|
62
|
+
it "handles SSL errors"
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "handles API errors" do
|
66
|
+
it "prevents no API key" do
|
67
|
+
RTFM.api_key = nil
|
68
|
+
lambda {
|
69
|
+
RTFM.moderate_image(@url)
|
70
|
+
}.must_raise(RTFM::AuthenticationError)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "handles bad API key" do
|
74
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
75
|
+
:status => 401, :body => MultiJson.dump({:error => "You're not authorized"})
|
76
|
+
)
|
77
|
+
error = lambda {
|
78
|
+
puts RTFM.moderate_image(@url)
|
79
|
+
}.must_raise(RTFM::AuthenticationError)
|
80
|
+
error.to_s.must_match /not authorized/
|
81
|
+
end
|
82
|
+
|
83
|
+
it "handles no money" do
|
84
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
85
|
+
:status => 402, :body => MultiJson.dump({:error => "You have no money"})
|
86
|
+
)
|
87
|
+
error = lambda {
|
88
|
+
puts RTFM.moderate_image(@url)
|
89
|
+
}.must_raise(RTFM::PaymentError)
|
90
|
+
error.to_s.must_match /no money/
|
91
|
+
end
|
92
|
+
|
93
|
+
it "handles bad account" do
|
94
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
95
|
+
:status => 403, :body => MultiJson.dump({:error => "You have no account"})
|
96
|
+
)
|
97
|
+
error = lambda {
|
98
|
+
puts RTFM.moderate_image(@url)
|
99
|
+
}.must_raise(RTFM::AccountError)
|
100
|
+
error.to_s.must_match /no account/
|
101
|
+
end
|
102
|
+
|
103
|
+
it "handles not found" do
|
104
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
105
|
+
:status => 404, :body => MultiJson.dump({:error => "Not Found"})
|
106
|
+
)
|
107
|
+
error = lambda {
|
108
|
+
puts RTFM.moderate_image(@url)
|
109
|
+
}.must_raise(RTFM::InvalidRequestError)
|
110
|
+
error.to_s.must_match /Not Found/
|
111
|
+
end
|
112
|
+
|
113
|
+
it "handles ratelimit" do
|
114
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
115
|
+
:status => 503, :body => MultiJson.dump({:error => "Too fast"})
|
116
|
+
)
|
117
|
+
error = lambda {
|
118
|
+
puts RTFM.moderate_image(@url)
|
119
|
+
}.must_raise(RTFM::RateLimitError)
|
120
|
+
error.to_s.must_match /Too fast/
|
121
|
+
end
|
122
|
+
|
123
|
+
it "handles malformed response on success" do
|
124
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
125
|
+
:status => 200, :body => "bullshit"
|
126
|
+
)
|
127
|
+
error = lambda {
|
128
|
+
puts RTFM.moderate_image(@url)
|
129
|
+
}.must_raise(RTFM::APIError)
|
130
|
+
error.to_s.must_match /bullshit/
|
131
|
+
end
|
132
|
+
|
133
|
+
it "handles malformed response on error" do
|
134
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
135
|
+
:status => 500, :body => "bullshit"
|
136
|
+
)
|
137
|
+
error = lambda {
|
138
|
+
puts RTFM.moderate_image(@url)
|
139
|
+
}.must_raise(RTFM::APIError)
|
140
|
+
error.to_s.must_match /bullshit/
|
141
|
+
end
|
142
|
+
|
143
|
+
it "handles malformed request" do
|
144
|
+
stub_request(:post, "https://1234:@rtfm.crowdflower.com/v1/images").to_return(
|
145
|
+
:status => 422, :body => MultiJson.dump({:error => "Bad url"})
|
146
|
+
)
|
147
|
+
error = lambda {
|
148
|
+
puts RTFM.moderate_image(@url)
|
149
|
+
}.must_raise(RTFM::APIError)
|
150
|
+
error.to_s.must_match /Bad url/
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crowdflower-rtfm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Van Pelt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: &70210985936740 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70210985936740
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: multi_json
|
27
|
+
requirement: &70210985936140 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70210985936140
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: minitest
|
38
|
+
requirement: &70210985935640 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70210985935640
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: &70210985935140 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70210985935140
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: jeweler
|
60
|
+
requirement: &70210985934580 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.8.3
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70210985934580
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: &70210985933940 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70210985933940
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: webmock
|
82
|
+
requirement: &70210985933220 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70210985933220
|
91
|
+
description: Real Time Foto Moderator (RTFM) is Crowdsourced Image Moderation. Keep
|
92
|
+
your app clean!
|
93
|
+
email: vanpelt@crowdflower.com
|
94
|
+
executables: []
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files:
|
97
|
+
- LICENSE.txt
|
98
|
+
- README.md
|
99
|
+
files:
|
100
|
+
- .document
|
101
|
+
- Gemfile
|
102
|
+
- Gemfile.lock
|
103
|
+
- LICENSE.txt
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- VERSION
|
107
|
+
- crowdflower-rtfm.gemspec
|
108
|
+
- examples/Gemfile
|
109
|
+
- examples/README.md
|
110
|
+
- examples/config.ru
|
111
|
+
- examples/webhook.rb
|
112
|
+
- examples/webhook_public.pem
|
113
|
+
- lib/crowdflower-rtfm.rb
|
114
|
+
- test/helper.rb
|
115
|
+
- test/test_rtfm.rb
|
116
|
+
homepage: http://dolores.github.com/rtfm-api
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
segments:
|
130
|
+
- 0
|
131
|
+
hash: -2682891135621693422
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 1.8.10
|
141
|
+
signing_key:
|
142
|
+
specification_version: 3
|
143
|
+
summary: Simple Ruby wrapper for the RTFM API
|
144
|
+
test_files: []
|