sift 1.1.6.2 → 4.5.0
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.
- checksums.yaml +5 -13
- data/.circleci/config.yml +105 -0
- data/.github/pull_request_template.md +12 -0
- data/.github/workflows/publishing_sift_ruby.yml +38 -0
- data/.gitignore +1 -0
- data/.jenkins/Jenkinsfile +103 -0
- data/HISTORY +104 -0
- data/README.md +351 -0
- data/examples/psp_merchant_management_apis.rb +105 -0
- data/examples/validation_apis.rb +47 -0
- data/lib/sift/client/decision/apply_to.rb +129 -0
- data/lib/sift/client/decision.rb +66 -0
- data/lib/sift/client.rb +845 -112
- data/lib/sift/error.rb +13 -0
- data/lib/sift/router.rb +41 -0
- data/lib/sift/utils/hash_getter.rb +15 -0
- data/lib/sift/validate/decision.rb +65 -0
- data/lib/sift/validate/primitive.rb +43 -0
- data/lib/sift/version.rb +2 -2
- data/lib/sift.rb +85 -11
- data/sift.gemspec +5 -3
- data/spec/fixtures/fake_responses.rb +16 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/client/decision/apply_to_spec.rb +262 -0
- data/spec/unit/client/decision_spec.rb +83 -0
- data/spec/unit/client_203_spec.rb +193 -0
- data/spec/unit/client_205_spec.rb +117 -0
- data/spec/unit/client_label_spec.rb +68 -11
- data/spec/unit/client_psp_merchant_spec.rb +133 -0
- data/spec/unit/client_spec.rb +556 -79
- data/spec/unit/client_validationapi_spec.rb +91 -0
- data/spec/unit/router_spec.rb +37 -0
- data/spec/unit/validate/decision_spec.rb +85 -0
- data/spec/unit/validate/primitive_spec.rb +73 -0
- data/test_integration_app/decisions_api/test_decisions_api.rb +31 -0
- data/test_integration_app/events_api/test_events_api.rb +843 -0
- data/test_integration_app/globals.rb +2 -0
- data/test_integration_app/main.rb +67 -0
- data/test_integration_app/psp_merchants_api/test_psp_merchant_api.rb +44 -0
- data/test_integration_app/score_api/test_score_api.rb +11 -0
- data/test_integration_app/verification_api/test_verification_api.rb +32 -0
- metadata +85 -28
- data/.travis.yml +0 -13
- data/README.rdoc +0 -85
- data/spec/unit/sift_spec.rb +0 -6
data/lib/sift/error.rb
ADDED
data/lib/sift/router.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "./version"
|
2
|
+
require_relative "./client"
|
3
|
+
|
4
|
+
module Sift
|
5
|
+
class Router
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def get(path, options = {})
|
10
|
+
serialize_body(options)
|
11
|
+
add_default_headers(options)
|
12
|
+
wrap_response(super(path, options))
|
13
|
+
end
|
14
|
+
|
15
|
+
def post(path, options = {})
|
16
|
+
serialize_body(options)
|
17
|
+
add_default_headers(options)
|
18
|
+
wrap_response(super(path, options))
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize_body(options)
|
22
|
+
options[:body] = MultiJson.dump(options[:body]) if options[:body]
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_default_headers(options)
|
26
|
+
options[:headers] = {
|
27
|
+
"User-Agent" => Sift::Client.user_agent
|
28
|
+
}.merge(options[:headers] || {})
|
29
|
+
end
|
30
|
+
|
31
|
+
def wrap_response(response)
|
32
|
+
Response.new(
|
33
|
+
response.body,
|
34
|
+
response.code,
|
35
|
+
response.response
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative "primitive"
|
2
|
+
|
3
|
+
module Sift
|
4
|
+
module Validate
|
5
|
+
class Decision
|
6
|
+
attr_reader :configs, :error_messages
|
7
|
+
|
8
|
+
def initialize(configs = {})
|
9
|
+
@configs = configs
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid_order?
|
13
|
+
run do
|
14
|
+
validate_key(:non_empty_string, :user_id, :order_id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def valid_session?
|
19
|
+
run do
|
20
|
+
validate_key(:non_empty_string, :user_id, :session_id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid_content?
|
25
|
+
run do
|
26
|
+
validate_key(:non_empty_string, :user_id, :content_id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid_user?
|
31
|
+
run do
|
32
|
+
validate_key(:non_empty_string, :user_id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def run
|
39
|
+
clear_errors!
|
40
|
+
yield
|
41
|
+
error_messages.empty?
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_primitive
|
45
|
+
Validate::Primitive
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_key(type, *keys)
|
49
|
+
keys.each do |key|
|
50
|
+
if error_message = validate_primitive.public_send(type, get(key))
|
51
|
+
error_messages << "#{key} #{error_message}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def clear_errors!
|
57
|
+
@error_messages = []
|
58
|
+
end
|
59
|
+
|
60
|
+
def get(key)
|
61
|
+
configs[key] || configs[key.to_s]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Sift
|
2
|
+
module Validate
|
3
|
+
class Primitive
|
4
|
+
ERROR_MESSAGES = {
|
5
|
+
non_empty_string: "must be a non-empty string",
|
6
|
+
numeric: "must be a number",
|
7
|
+
string_or_number: "must be a string or a number",
|
8
|
+
}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def non_empty_string(value)
|
12
|
+
if !value.is_a?(String)
|
13
|
+
"#{ERROR_MESSAGES[:non_empty_string]}, got #{value.class}"
|
14
|
+
elsif value.empty?
|
15
|
+
empty_string_message(:non_empty_string)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def numeric(value)
|
20
|
+
if !value.is_a?(Numeric)
|
21
|
+
ERROR_MESSAGES[:numeric]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def string_or_number(value)
|
26
|
+
if (value.is_a?(String) && value.empty?)
|
27
|
+
return empty_string_message(:string_or_number)
|
28
|
+
end
|
29
|
+
|
30
|
+
if value.nil? || !(value.is_a?(String) || value.is_a?(Numeric))
|
31
|
+
"#{ERROR_MESSAGES[:string_or_number]}, got #{value.class}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def empty_string_message(message)
|
38
|
+
"#{ERROR_MESSAGES[message]}, got an empty string"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/sift/version.rb
CHANGED
data/lib/sift.rb
CHANGED
@@ -1,23 +1,98 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative './sift/version'
|
2
|
+
require_relative './sift/client'
|
3
|
+
require 'erb'
|
3
4
|
|
4
5
|
module Sift
|
5
6
|
|
6
|
-
# Returns the path for the
|
7
|
-
def self.
|
8
|
-
"/v#{
|
7
|
+
# Returns the path for the specified API version
|
8
|
+
def self.rest_api_path(version=API_VERSION)
|
9
|
+
"/v#{version}/events"
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
"/v#{
|
12
|
+
# Returns the path for the specified API version
|
13
|
+
def self.verification_api_send_path(version=API_VERSION)
|
14
|
+
"/v#{version}/verification/send"
|
14
15
|
end
|
15
|
-
|
16
|
-
#
|
16
|
+
|
17
|
+
# Returns the path for the specified API version
|
18
|
+
def self.verification_api_resend_path(version=API_VERSION)
|
19
|
+
"/v#{version}/verification/resend"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the path for the specified API version
|
23
|
+
def self.verification_api_check_path(version=API_VERSION)
|
24
|
+
"/v#{version}/verification/check"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the Score API path for the specified user ID and API version
|
28
|
+
def self.score_api_path(user_id, version=API_VERSION)
|
29
|
+
"/v#{version}/score/#{ERB::Util.url_encode(user_id)}/"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the User Score API path for the specified user ID and API version
|
33
|
+
def self.user_score_api_path(user_id, version=API_VERSION)
|
34
|
+
"/v#{version}/users/#{ERB::Util.url_encode(user_id)}/score"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the users API path for the specified user ID and API version
|
38
|
+
def self.users_label_api_path(user_id, version=API_VERSION)
|
39
|
+
"/v#{version}/users/#{ERB::Util.url_encode(user_id)}/labels"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the path for the Workflow Status API
|
43
|
+
def self.workflow_status_path(account_id, run_id)
|
44
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
45
|
+
"/workflows/runs/#{ERB::Util.url_encode(run_id)}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the path for User Decisions API
|
49
|
+
def self.user_decisions_api_path(account_id, user_id)
|
50
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
51
|
+
"/users/#{ERB::Util.url_encode(user_id)}/decisions"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the path for Orders Decisions API
|
55
|
+
def self.order_decisions_api_path(account_id, order_id)
|
56
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
57
|
+
"/orders/#{ERB::Util.url_encode(order_id)}/decisions"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the path for Session Decisions API
|
61
|
+
def self.session_decisions_api_path(account_id, user_id, session_id)
|
62
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
63
|
+
"/users/#{ERB::Util.url_encode(user_id)}" \
|
64
|
+
"/sessions/#{ERB::Util.url_encode(session_id)}/decisions"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the path for Content Decisions API
|
68
|
+
def self.content_decisions_api_path(account_id, user_id, content_id)
|
69
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
70
|
+
"/users/#{ERB::Util.url_encode(user_id)}" \
|
71
|
+
"/content/#{ERB::Util.url_encode(content_id)}/decisions"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the path for psp Merchant API
|
75
|
+
def self.psp_merchant_api_path(account_id)
|
76
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
77
|
+
"/psp_management/merchants"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the path for psp Merchant with id
|
81
|
+
def self.psp_merchant_id_api_path(account_id, merchant_id)
|
82
|
+
"/v3/accounts/#{ERB::Util.url_encode(account_id)}" \
|
83
|
+
"/psp_management/merchants/#{ERB::Util.url_encode(merchant_id)}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Module-scoped public API key
|
17
87
|
class << self
|
18
88
|
attr_accessor :api_key
|
19
89
|
end
|
20
90
|
|
91
|
+
# Module-scoped account ID
|
92
|
+
class << self
|
93
|
+
attr_accessor :account_id
|
94
|
+
end
|
95
|
+
|
21
96
|
# Sets the Output logger to use within the client. This can be left uninitializaed
|
22
97
|
# but is useful for debugging.
|
23
98
|
def self.logger=(logger)
|
@@ -39,5 +114,4 @@ module Sift
|
|
39
114
|
def self.fatal(msg)
|
40
115
|
@logger.fatal(msg) if @logger
|
41
116
|
end
|
42
|
-
|
43
117
|
end
|
data/sift.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "sift"
|
7
7
|
s.version = Sift::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Fred Sadaghiani", "Yoav Schatzberg"]
|
9
|
+
s.authors = ["Fred Sadaghiani", "Yoav Schatzberg", "Jacob Burnim"]
|
10
10
|
s.email = ["support@siftscience.com"]
|
11
11
|
s.homepage = "http://siftscience.com"
|
12
12
|
s.summary = %q{Sift Science Ruby API Gem}
|
@@ -20,8 +20,10 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
22
|
# Gems that must be intalled for sift to compile and build
|
23
|
-
s.add_development_dependency "rspec", "
|
24
|
-
s.add_development_dependency "
|
23
|
+
s.add_development_dependency "rspec", "~> 3.5"
|
24
|
+
s.add_development_dependency "rspec_junit_formatter"
|
25
|
+
s.add_development_dependency "pry"
|
26
|
+
s.add_development_dependency "webmock", ">= 1.16.0", "< 2"
|
25
27
|
|
26
28
|
# Gems that must be intalled for sift to work
|
27
29
|
s.add_dependency "httparty", ">= 0.11.0"
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,262 @@
|
|
1
|
+
require_relative "../../../spec_helper"
|
2
|
+
|
3
|
+
require "sift/client/decision/apply_to"
|
4
|
+
|
5
|
+
module Sift
|
6
|
+
class Client
|
7
|
+
class Decision
|
8
|
+
describe ApplyTo do
|
9
|
+
let(:decision_id) { "block_it" }
|
10
|
+
let(:api_key) { "customer_key" }
|
11
|
+
let(:decision) { Decision.new(api_key, "account_id") }
|
12
|
+
|
13
|
+
describe "attributes" do
|
14
|
+
ApplyTo::PROPERTIES.each do |attribute|
|
15
|
+
it "can read #{attribute} whether it is a symbol or string" do
|
16
|
+
expected_value = "right_#{attribute}#{Time.now.to_i}"
|
17
|
+
string_hash = {}
|
18
|
+
string_hash[attribute] = expected_value
|
19
|
+
|
20
|
+
applier = ApplyTo.new(api_key, "id", string_hash)
|
21
|
+
expect(applier.public_send(attribute)).to(
|
22
|
+
eq(expected_value),
|
23
|
+
"#{attribute} did not read the right string value"
|
24
|
+
)
|
25
|
+
|
26
|
+
symbol_hash = {}
|
27
|
+
symbol_hash[attribute.to_sym] = expected_value
|
28
|
+
|
29
|
+
applier = ApplyTo.new(api_key, "id", symbol_hash)
|
30
|
+
expect(applier.public_send(attribute)).to(
|
31
|
+
eq(expected_value),
|
32
|
+
"#{attribute} did not read the right symbol value"
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#run" do
|
39
|
+
it "will send a request to block user" do
|
40
|
+
configs = {
|
41
|
+
source: "manual",
|
42
|
+
analyst: "foobar@example.com",
|
43
|
+
description: "be blocking errrday allday",
|
44
|
+
user_id: "user_1234",
|
45
|
+
time: 1234,
|
46
|
+
fake_param: "this should not exist"
|
47
|
+
}
|
48
|
+
|
49
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
50
|
+
request_body = MultiJson.dump({
|
51
|
+
source: configs[:source],
|
52
|
+
description: configs[:description],
|
53
|
+
analyst: configs[:analyst],
|
54
|
+
decision_id: decision_id,
|
55
|
+
time: 1234
|
56
|
+
})
|
57
|
+
|
58
|
+
response_body = {
|
59
|
+
"entity" => {
|
60
|
+
"id" => "USER_ID",
|
61
|
+
"type" => "user"
|
62
|
+
},
|
63
|
+
"decision" => {
|
64
|
+
"id" => decision_id
|
65
|
+
},
|
66
|
+
"time" => Time.now.to_i
|
67
|
+
}
|
68
|
+
|
69
|
+
stub_request(:post, put_auth_in_url(api_key, applier.send(:path)))
|
70
|
+
.with(body: request_body)
|
71
|
+
.to_return(body: MultiJson.dump(response_body))
|
72
|
+
|
73
|
+
response = applier.run
|
74
|
+
|
75
|
+
expect(response.ok?).to be(true)
|
76
|
+
expect(response.body).to eq(response_body)
|
77
|
+
end
|
78
|
+
|
79
|
+
context "without a valid user_id or order_id" do
|
80
|
+
it "will return a response object with the error message" do
|
81
|
+
configs = {
|
82
|
+
source: "manual",
|
83
|
+
analyst: "foobar@example.com",
|
84
|
+
description: "be blocking errrday allday",
|
85
|
+
decision: decision,
|
86
|
+
user_id: "user_1234",
|
87
|
+
"order_id" => nil
|
88
|
+
}
|
89
|
+
|
90
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
91
|
+
|
92
|
+
response = applier.run
|
93
|
+
non_empty_string_error =
|
94
|
+
Validate::Primitive::ERROR_MESSAGES[:non_empty_string]
|
95
|
+
error_message = "order_id #{non_empty_string_error}, got NilClass"
|
96
|
+
|
97
|
+
expect(response.ok?).to be(false)
|
98
|
+
expect(response.body["error_message"]).to eq(error_message)
|
99
|
+
|
100
|
+
## Invalid user_id
|
101
|
+
|
102
|
+
configs.delete(:user_id)
|
103
|
+
configs.delete("order_id")
|
104
|
+
|
105
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
106
|
+
|
107
|
+
response = applier.run
|
108
|
+
error_message = "user_id #{non_empty_string_error}, got NilClass"
|
109
|
+
|
110
|
+
expect(response.ok?).to be(false)
|
111
|
+
expect(response.body["error_message"]).to eq(error_message)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "without a valid user_id or session_id" do
|
116
|
+
it "will return a response object with the error message" do
|
117
|
+
configs = {
|
118
|
+
source: "manual",
|
119
|
+
analyst: "foobar@example.com",
|
120
|
+
description: "be blocking errrday allday",
|
121
|
+
decision: decision,
|
122
|
+
"session_id" => nil,
|
123
|
+
user_id: "user_1234"
|
124
|
+
}
|
125
|
+
|
126
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
127
|
+
|
128
|
+
response = applier.run
|
129
|
+
non_empty_string_error =
|
130
|
+
Validate::Primitive::ERROR_MESSAGES[:non_empty_string]
|
131
|
+
error_message = "session_id #{non_empty_string_error}, got NilClass"
|
132
|
+
|
133
|
+
expect(response.ok?).to be(false)
|
134
|
+
expect(response.body["error_message"]).to eq(error_message)
|
135
|
+
|
136
|
+
## Invalid user_id
|
137
|
+
|
138
|
+
configs.delete(:user_id)
|
139
|
+
configs.delete("session_id")
|
140
|
+
|
141
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
142
|
+
|
143
|
+
response = applier.run
|
144
|
+
error_message = "user_id #{non_empty_string_error}, got NilClass"
|
145
|
+
|
146
|
+
expect(response.ok?).to be(false)
|
147
|
+
expect(response.body["error_message"]).to eq(error_message)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when api returns an error code" do
|
152
|
+
it "will return a response with the information" do
|
153
|
+
configs = {
|
154
|
+
source: "manual",
|
155
|
+
description: "be blocking errrday allday",
|
156
|
+
decision: decision,
|
157
|
+
user_id: "user_1234"
|
158
|
+
}
|
159
|
+
|
160
|
+
applier = ApplyTo.new(api_key, decision_id, configs)
|
161
|
+
request_body = MultiJson.dump(applier.send(:request_body))
|
162
|
+
|
163
|
+
response_body = {
|
164
|
+
"error" => "not_found",
|
165
|
+
"description" => "No decision with id non_existent_decision_id"
|
166
|
+
}
|
167
|
+
|
168
|
+
stub_request(:post, put_auth_in_url(api_key, applier.send(:path)))
|
169
|
+
.with(body: request_body)
|
170
|
+
.to_return(body: MultiJson.dump(response_body), status: 404)
|
171
|
+
|
172
|
+
response = applier.run
|
173
|
+
|
174
|
+
expect(response.ok?).to be(false)
|
175
|
+
expect(response.body).to eq(response_body)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#run" do
|
181
|
+
it "will construct the right path given the configs" do
|
182
|
+
user_id = "bad_user@example.com"
|
183
|
+
order_id = "ORDER_1235"
|
184
|
+
|
185
|
+
applier = ApplyTo.new(api_key, decision_id, {
|
186
|
+
user_id: user_id,
|
187
|
+
account_id: decision.account_id,
|
188
|
+
})
|
189
|
+
|
190
|
+
path = Client::API3_ENDPOINT +
|
191
|
+
"/v3/accounts/#{decision.account_id}" +
|
192
|
+
"/users/#{CGI.escape(user_id)}" +
|
193
|
+
"/decisions"
|
194
|
+
|
195
|
+
expect("https://api3.siftscience.com/v3/accounts/account_id" +
|
196
|
+
"/users/bad_user%40example.com/decisions").to eq(path)
|
197
|
+
|
198
|
+
applier = ApplyTo.new(api_key, decision_id, {
|
199
|
+
user_id: user_id,
|
200
|
+
account_id: decision.account_id,
|
201
|
+
order_id: order_id
|
202
|
+
})
|
203
|
+
|
204
|
+
path = Client::API3_ENDPOINT +
|
205
|
+
"/v3/accounts/#{decision.account_id}/users/" +
|
206
|
+
"#{CGI.escape(user_id)}/orders/#{CGI.escape(order_id)}" +
|
207
|
+
"/decisions"
|
208
|
+
|
209
|
+
expect("https://api3.siftscience.com/v3/accounts/account_id" +
|
210
|
+
"/users/bad_user%40example.com/orders/ORDER_1235/decisions").to eq(path)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#run" do
|
215
|
+
it "will construct the right path given the configs" do
|
216
|
+
user_id = "bad_user@example.com"
|
217
|
+
session_id = "gigtleqddo84l8cm15qe4il"
|
218
|
+
|
219
|
+
applier = ApplyTo.new(api_key, decision_id, {
|
220
|
+
user_id: user_id,
|
221
|
+
account_id: decision.account_id,
|
222
|
+
})
|
223
|
+
|
224
|
+
path = Client::API3_ENDPOINT +
|
225
|
+
"/v3/accounts/#{decision.account_id}" +
|
226
|
+
"/users/#{CGI.escape(user_id)}" +
|
227
|
+
"/decisions"
|
228
|
+
|
229
|
+
expect("https://api3.siftscience.com/v3/accounts/account_id" +
|
230
|
+
"/users/bad_user%40example.com/decisions").to eq(path)
|
231
|
+
|
232
|
+
applier = ApplyTo.new(api_key, decision_id, {
|
233
|
+
user_id: user_id,
|
234
|
+
account_id: decision.account_id,
|
235
|
+
session_id: session_id
|
236
|
+
})
|
237
|
+
|
238
|
+
path = Client::API3_ENDPOINT +
|
239
|
+
"/v3/accounts/#{decision.account_id}/users/" +
|
240
|
+
"#{CGI.escape(user_id)}/sessions/#{CGI.escape(session_id)}" +
|
241
|
+
"/decisions"
|
242
|
+
|
243
|
+
expect("https://api3.siftscience.com/v3/accounts/account_id" +
|
244
|
+
"/users/bad_user%40example.com/sessions/gigtleqddo84l8cm15qe4il/decisions").to eq(path)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
# TODO(Kaoru): When we move to webmock 2 we won't need to do this
|
250
|
+
# hackery
|
251
|
+
#
|
252
|
+
# https://github.com/bblimke/webmock/blob/master/CHANGELOG.md#200
|
253
|
+
#
|
254
|
+
def put_auth_in_url(api_key, url)
|
255
|
+
protocal, uri = url.split(/(?<=https\:\/\/)/)
|
256
|
+
|
257
|
+
protocal + api_key + "@" + uri
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|