Skip to content

Commit c6166aa

Browse files
authored
Merge pull request #56 from SiftScience/kkarpierz_v205_ruby
(Gary L.) Added Content Decisions to library, incremented version to V205
2 parents b358d62 + dd0c247 commit c6166aa

File tree

9 files changed

+108
-16
lines changed

9 files changed

+108
-16
lines changed

HISTORY

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
=== 3.0.0.0 2018-03-05
2+
* adds support for v205 of Sift Science's APIs
3+
* v205 APIs are now called by default -- this is an incompatible change
4+
(use :version => 204 to call the previous API version)
5+
* Add content level decisions in Apply Decisions APIs.
6+
17
=== 2.2.1.0 2018-02-12
28
* Add session level decisions in Apply Decisions APIs.
39

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ response = client.apply_decision({
140140
user_id: "[email protected]"
141141
})
142142

143-
# apply decision to "bob@example.com"'s order
143+
# apply decision to "john@example.com"'s order
144144
response = client.apply_decision({
145145
decision_id: "block_bad_order",
146146
source: "manual_review",
@@ -149,7 +149,7 @@ response = client.apply_decision({
149149
order_id: "ORDER_1234"
150150
})
151151

152-
# apply decision to "bob@example.com"'s session
152+
# apply decision to "john@example.com"'s session
153153
response = client.apply_decision({
154154
decision_id: "block_bad_session",
155155
source: "manual_review",
@@ -158,6 +158,16 @@ response = client.apply_decision({
158158
session_id: "SESSION_ID_1234"
159159
})
160160

161+
# apply decision to "[email protected]"'s content
162+
response = client.apply_decision({
163+
decision_id: "block_bad_session",
164+
source: "manual_review",
165+
analyst: "bob@your_company.com",
166+
user_id: "[email protected]",
167+
content_id: "CONTENT_ID_1234"
168+
})
169+
170+
161171
# Make sure you handle the response after applying a decision:
162172

163173
if response.ok?
@@ -196,6 +206,9 @@ response = client.get_user_decisions('example_user_id')
196206

197207
# Get the latest decisions for an order
198208
response = client.get_order_decisions('example_order_id')
209+
210+
# Get the latest decisions for an content
211+
response = client.get_content_decisions('example_user_id', 'example_order_id')
199212
```
200213

201214
## Response Object

lib/sift.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ def self.order_decisions_api_path(account_id, order_id)
3333
"/v3/accounts/#{account_id}/orders/#{order_id}/decisions"
3434
end
3535

36+
# Returns the path for Content Decisions API
37+
def self.content_decisions_api_path(account_id, user_id, content_id)
38+
"/v3/accounts/#{account_id}/users/#{user_id}/content/#{content_id}/decisions"
39+
end
40+
3641
# Module-scoped public API key
3742
class << self
3843
attr_accessor :api_key

lib/sift/client.rb

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def self.user_agent
118118
#
119119
# :version::
120120
# The version of the Events API, Score API, and Labels API to call.
121-
# By default, version 204.
121+
# By default, version 205.
122122
#
123123
# :path::
124124
# The URL path to use for Events API path. By default, the
@@ -132,7 +132,7 @@ def initialize(opts = {})
132132
@timeout = opts[:timeout] || 2 # 2-second timeout by default
133133
@path = opts[:path] || Sift.rest_api_path(@version)
134134

135-
raise("api_key must be a non-empty string") if !@api_key.is_a?(String) || @api_key.empty?
135+
raise("api_key") if !@api_key.is_a?(String) || @api_key.empty?
136136
raise("path must be a non-empty string") if !@path.is_a?(String) || @path.empty?
137137
end
138138

@@ -504,6 +504,47 @@ def get_order_decisions(order_id, opts = {})
504504
Response.new(response.body, response.code, response.response)
505505
end
506506

507+
508+
# Gets the decision status of a piece of content.
509+
#
510+
# See https://siftscience.com/developers/docs/ruby/decisions-api/decision-status .
511+
#
512+
# ==== Parameters
513+
#
514+
# user_id::
515+
# The ID of the owner of the content.
516+
#
517+
# content_id::
518+
# The ID of a piece of content.
519+
#
520+
# opts (optional)::
521+
# A Hash of optional parameters for this request --
522+
#
523+
# :account_id::
524+
# Overrides the API key for this call.
525+
#
526+
# :api_key::
527+
# Overrides the API key for this call.
528+
#
529+
# :timeout::
530+
# Overrides the timeout (in seconds) for this call.
531+
#
532+
def get_content_decisions(user_id, content_id, opts = {})
533+
account_id = opts[:account_id] || @account_id
534+
api_key = opts[:api_key] || @api_key
535+
timeout = opts[:timeout] || @timeout
536+
537+
options = {
538+
:headers => { "User-Agent" => user_agent },
539+
:basic_auth => { :username => api_key, :password => "" }
540+
}
541+
options.merge!(:timeout => timeout) unless timeout.nil?
542+
543+
uri = API3_ENDPOINT + Sift.content_decisions_api_path(account_id, user_id, content_id)
544+
response = self.class.get(uri, options)
545+
Response.new(response.body, response.code, response.response)
546+
end
547+
507548
def decisions(opts = {})
508549
decision_instance.list(opts)
509550
end

lib/sift/client/decision/apply_to.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class ApplyTo
1515
description
1616
order_id
1717
session_id
18+
content_id
1819
user_id
1920
account_id
2021
time
@@ -93,11 +94,17 @@ def applying_to_session?
9394
configs.has_key?("session_id") || configs.has_key?(:session_id)
9495
end
9596

97+
def applying_to_content?
98+
configs.has_key?("content_id") || configs.has_key?(:content_id)
99+
end
100+
96101
def path
97102
if applying_to_order?
98103
"#{user_path}/orders/#{CGI.escape(order_id)}/decisions"
99104
elsif applying_to_session?
100105
"#{user_path}/sessions/#{CGI.escape(session_id)}/decisions"
106+
elsif applying_to_content?
107+
"#{user_path}/content/#{CGI.escape(content_id)}/decisions"
101108
else
102109
"#{user_path}/decisions"
103110
end

lib/sift/validate/decision.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ def valid_session?
2020
validate_key(:non_empty_string, :user_id, :session_id)
2121
end
2222
end
23+
24+
def valid_content?
25+
run do
26+
validate_key(:non_empty_string, :user_id, :content_id)
27+
end
28+
end
2329

2430
def valid_user?
2531
run do

lib/sift/version.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
module Sift
2-
VERSION = "2.2.1"
3-
API_VERSION = "204"
2+
VERSION = "3.0.0"
3+
API_VERSION = "205"
44
end

spec/unit/client_label_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def valid_label_properties_203
2525
response_json = { :status => 0, :error_message => "OK" }
2626
user_id = "frodo_baggins"
2727

28-
stub_request(:post, "https://api.siftscience.com/v204/users/frodo_baggins/labels")
28+
stub_request(:post, "https://api.siftscience.com/v205/users/frodo_baggins/labels")
2929
.with(:body => ('{"$abuse_type":"content_abuse","$is_bad":true,"$description":"Listed a fake item","$type":"$label","$api_key":"foobar"}'))
3030
.to_return(:body => MultiJson.dump(response_json), :status => 200,
3131
:headers => {"content-type"=>"application/json; charset=UTF-8",
@@ -45,7 +45,7 @@ def valid_label_properties_203
4545
user_id = "frodo_baggins"
4646

4747
stub_request(:delete,
48-
"https://api.siftscience.com/v204/users/frodo_baggins/labels?api_key=foobar&abuse_type=payment_abuse")
48+
"https://api.siftscience.com/v205/users/frodo_baggins/labels?api_key=foobar&abuse_type=payment_abuse")
4949
.to_return(:status => 204)
5050

5151
api_key = "foobar"

spec/unit/client_spec.rb

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def fully_qualified_api_endpoint
169169
it "Successfuly handles an event and returns OK" do
170170
response_json = { :status => 0, :error_message => "OK" }
171171

172-
stub_request(:post, "https://api.siftscience.com/v204/events").
172+
stub_request(:post, "https://api.siftscience.com/v205/events").
173173
with { |request|
174174
parsed_body = JSON.parse(request.body)
175175
expect(parsed_body).to include("$buyer_user_id" => "123456")
@@ -190,7 +190,7 @@ def fully_qualified_api_endpoint
190190

191191
it "Successfully submits event with overridden key" do
192192
response_json = { :status => 0, :error_message => "OK"}
193-
stub_request(:post, "https://api.siftscience.com/v204/events").
193+
stub_request(:post, "https://api.siftscience.com/v205/events").
194194
with { | request|
195195
parsed_body = JSON.parse(request.body)
196196
expect(parsed_body).to include("$buyer_user_id" => "123456")
@@ -212,7 +212,7 @@ def fully_qualified_api_endpoint
212212
it "Successfully scrubs nils" do
213213
response_json = { :status => 0, :error_message => "OK" }
214214

215-
stub_request(:post, "https://api.siftscience.com/v204/events")
215+
stub_request(:post, "https://api.siftscience.com/v205/events")
216216
.with { |request|
217217
parsed_body = JSON.parse(request.body)
218218
expect(parsed_body).not_to include("fake_property")
@@ -241,7 +241,7 @@ def fully_qualified_api_endpoint
241241
api_key = "foobar"
242242
response_json = score_response_json
243243

244-
stub_request(:get, "https://api.siftscience.com/v204/score/247019/?api_key=foobar")
244+
stub_request(:get, "https://api.siftscience.com/v205/score/247019/?api_key=foobar")
245245
.to_return(:status => 200, :body => MultiJson.dump(response_json),
246246
:headers => {"content-type"=>"application/json; charset=UTF-8",
247247
"content-length"=> "74"})
@@ -259,7 +259,7 @@ def fully_qualified_api_endpoint
259259
api_key = "foobar"
260260
response_json = score_response_json
261261

262-
stub_request(:get, "https://api.siftscience.com/v204/score/247019/?api_key=overridden")
262+
stub_request(:get, "https://api.siftscience.com/v205/score/247019/?api_key=overridden")
263263
.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
264264

265265
response = Sift::Client.new(:api_key => api_key)
@@ -280,7 +280,7 @@ def fully_qualified_api_endpoint
280280
:score_response => score_response_json
281281
}
282282

283-
stub_request(:post, "https://api.siftscience.com/v204/events?return_score=true")
283+
stub_request(:post, "https://api.siftscience.com/v205/events?return_score=true")
284284
.to_return(:status => 200, :body => MultiJson.dump(response_json),
285285
:headers => {"content-type"=>"application/json; charset=UTF-8",
286286
"content-length"=> "74"})
@@ -304,7 +304,7 @@ def fully_qualified_api_endpoint
304304
:score_response => action_response_json
305305
}
306306

307-
stub_request(:post, "https://api.siftscience.com/v204/events?return_action=true")
307+
stub_request(:post, "https://api.siftscience.com/v205/events?return_action=true")
308308
.to_return(:status => 200, :body => MultiJson.dump(response_json),
309309
:headers => {"content-type"=>"application/json; charset=UTF-8",
310310
"content-length"=> "74"})
@@ -332,7 +332,7 @@ def fully_qualified_api_endpoint
332332
}
333333

334334
stub_request(:post,
335-
"https://api.siftscience.com/v204/events?return_workflow_status=true&abuse_types=legacy,payment_abuse")
335+
"https://api.siftscience.com/v205/events?return_workflow_status=true&abuse_types=legacy,payment_abuse")
336336
.to_return(:status => 200, :body => MultiJson.dump(response_json),
337337
:headers => {"content-type"=>"application/json; charset=UTF-8",
338338
"content-length"=> "74"})
@@ -390,4 +390,18 @@ def fully_qualified_api_endpoint
390390
expect(response.body["decisions"]["payment_abuse"]["decision"]["id"]).to eq("decision7")
391391
end
392392

393+
394+
it "Successfully make an content decisions request" do
395+
response_text = '{"decisions":{"content_abuse":{"decision":{"id":"decision7"},"time":1468599638005,"webhook_succeeded":false}}}'
396+
397+
stub_request(:get, "https://foobar:@api3.siftscience.com/v3/accounts/ACCT/users/USER/content/example_content/decisions")
398+
.to_return(:status => 200, :body => response_text, :headers => {})
399+
400+
client = Sift::Client.new(:api_key => "foobar", :account_id => "ACCT")
401+
response = client.get_content_decisions("USER", "example_content", :timeout => 3)
402+
403+
expect(response.ok?).to eq(true)
404+
expect(response.body["decisions"]["content_abuse"]["decision"]["id"]).to eq("decision7")
405+
end
406+
393407
end

0 commit comments

Comments
 (0)