Skip to content

Commit

Permalink
(For Jintae or Gary) Add session level decision (#54)
Browse files Browse the repository at this point in the history
* Add support for session level decisions
  • Loading branch information
mjouahri authored Feb 13, 2018
1 parent 23df1e1 commit e92b887
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 7 deletions.
3 changes: 3 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
=== 2.2.0.0 2018-02-12
* Add session level decisions in Apply Decisions APIs.

=== 2.0.0.0 2016-07-19
* adds support for v204 of Sift Science's APIs
* adds Workflow Status API, User Decisions API, Order Decisions API
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ To learn more about the decisions endpoint visit our [developer docs](https://si
Get a list of your decisions.

**Optional Params**
- `entity_type`: `:user` or `:order`
- `entity_type`: `:user` or `:order` or `:session`
- `abuse_types`: `["payment_abuse", "content_abuse", "content_abuse",
"account_abuse", "legacy"]`
"account_abuse", "legacy", "account_takeover"]`

**Returns**

Expand Down Expand Up @@ -124,6 +124,7 @@ Applies a decision to an entity. Visit our [developer docs](http://siftscience.c

**Other Params**
- `order_id`: when applying a decision to an order, you must pass in the `order_id`
- `session_id`: when applying a decision to a session, you must pass in the `session_id`
- `analyst`: when `source` is set to `manual_review`, this field *is required*

**Returns**
Expand All @@ -148,6 +149,15 @@ response = client.apply_decision({
order_id: "ORDER_1234"
})

# apply decision to "[email protected]"'s session
response = client.apply_decision({
decision_id: "block_bad_session",
source: "manual_review",
analyst: "bob@your_company.com",
user_id: "[email protected]",
session_id: "SESSION_ID_1234"
})

# Make sure you handle the response after applying a decision:

if response.ok?
Expand Down
9 changes: 9 additions & 0 deletions lib/sift/client/decision/apply_to.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class ApplyTo
analyst
description
order_id
session_id
user_id
account_id
time
Expand Down Expand Up @@ -75,6 +76,8 @@ def errors

if applying_to_order?
validator.valid_order?
elsif applying_to_session?
validator.valid_session?
else
validator.valid_user?
end
Expand All @@ -86,9 +89,15 @@ def applying_to_order?
configs.has_key?("order_id") || configs.has_key?(:order_id)
end

def applying_to_session?
configs.has_key?("session_id") || configs.has_key?(:session_id)
end

def path
if applying_to_order?
"#{user_path}/orders/#{CGI.escape(order_id)}/decisions"
elsif applying_to_session?
"#{user_path}/sessions/#{CGI.escape(session_id)}/decisions"
else
"#{user_path}/decisions"
end
Expand Down
6 changes: 6 additions & 0 deletions lib/sift/validate/decision.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ def valid_order?
end
end

def valid_session?
run do
validate_key(:non_empty_string, :user_id, :session_id)
end
end

def valid_user?
run do
validate_key(:non_empty_string, :user_id)
Expand Down
2 changes: 1 addition & 1 deletion lib/sift/version.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Sift
VERSION = "2.1.1"
VERSION = "2.2.0"
API_VERSION = "204"
end
80 changes: 76 additions & 4 deletions spec/unit/client/decision/apply_to_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,42 @@ class Decision
end
end

context "without a valid user_id or session_id" do
it "will return a response object with the error message" do
configs = {
source: "manual",
analyst: "[email protected]",
description: "be blocking errrday allday",
decision: decision,
"session_id" => nil,
user_id: "user_1234"
}

applier = ApplyTo.new(api_key, decision_id, configs)

response = applier.run
non_empty_string_error =
Validate::Primitive::ERROR_MESSAGES[:non_empty_string]
error_message = "session_id #{non_empty_string_error}, got NilClass"

expect(response.ok?).to be(false)
expect(response.body["error_message"]).to eq(error_message)

## Invalid user_id

configs.delete(:user_id)
configs.delete("session_id")

applier = ApplyTo.new(api_key, decision_id, configs)

response = applier.run
error_message = "user_id #{non_empty_string_error}, got NilClass"

expect(response.ok?).to be(false)
expect(response.body["error_message"]).to eq(error_message)
end
end

context "when api returns an error code" do
it "will return a response with the information" do
configs = {
Expand Down Expand Up @@ -141,7 +177,7 @@ class Decision
end
end

describe "private#path" do
describe "#run" do
it "will construct the right path given the configs" do
user_id = "[email protected]"
order_id = "ORDER_1235"
Expand All @@ -156,8 +192,8 @@ class Decision
"/users/#{CGI.escape(user_id)}" +
"/decisions"


expect(applier.send(:path)).to eq(path)
expect("https://api3.siftscience.com/v3/accounts/account_id" +
"/users/bad_user%40example.com/decisions").to eq(path)

applier = ApplyTo.new(api_key, decision_id, {
user_id: user_id,
Expand All @@ -169,11 +205,47 @@ class Decision
"/v3/accounts/#{decision.account_id}/users/" +
"#{CGI.escape(user_id)}/orders/#{CGI.escape(order_id)}" +
"/decisions"

expect("https://api3.siftscience.com/v3/accounts/account_id" +
"/users/bad_user%40example.com/orders/ORDER_1235/decisions").to eq(path)
end
end

describe "#run" do
it "will construct the right path given the configs" do
user_id = "[email protected]"
session_id = "gigtleqddo84l8cm15qe4il"

applier = ApplyTo.new(api_key, decision_id, {
user_id: user_id,
account_id: decision.account_id,
})

path = Client::API3_ENDPOINT +
"/v3/accounts/#{decision.account_id}" +
"/users/#{CGI.escape(user_id)}" +
"/decisions"

expect(applier.send(:path)).to eq(path)
expect("https://api3.siftscience.com/v3/accounts/account_id" +
"/users/bad_user%40example.com/decisions").to eq(path)

applier = ApplyTo.new(api_key, decision_id, {
user_id: user_id,
account_id: decision.account_id,
session_id: session_id
})

path = Client::API3_ENDPOINT +
"/v3/accounts/#{decision.account_id}/users/" +
"#{CGI.escape(user_id)}/sessions/#{CGI.escape(session_id)}" +
"/decisions"

expect("https://api3.siftscience.com/v3/accounts/account_id" +
"/users/bad_user%40example.com/sessions/gigtleqddo84l8cm15qe4il/decisions").to eq(path)
end
end


# TODO(Kaoru): When we move to webmock 2 we won't need to do this
# hackery
#
Expand Down

0 comments on commit e92b887

Please sign in to comment.