sift 1.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +43 -0
- data/HISTORY +88 -0
- data/LICENSE +19 -0
- data/README.md +253 -0
- data/lib/sift/client/decision/apply_to.rb +129 -0
- data/lib/sift/client/decision.rb +66 -0
- data/lib/sift/client.rb +672 -88
- 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 -1
- data/lib/sift.rb +61 -9
- data/sift.gemspec +8 -7
- data/spec/fixtures/fake_responses.rb +16 -0
- data/spec/spec_helper.rb +3 -3
- 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_label_spec.rb +68 -12
- data/spec/unit/client_spec.rb +484 -48
- 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
- metadata +83 -54
- data/README.rdoc +0 -40
- data/spec/unit/sift_spec.rb +0 -6
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 57a679adbe12a556895633060cde177cf89fcb06
|
4
|
+
data.tar.gz: d3eff77b83c2ba5696c4c391f82d592a8df7443a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5809b998556c975ff30faceacf5468a812e815dead3e836640343fe681c1d612192a9a26615f8a0c35c4c13a3cb9b232f3aff1bbf7649d6b3e6c8250cd7f2896
|
7
|
+
data.tar.gz: 8b941c79e41784d1452f8ae4fe8b1052f7f32ed3954f8afb16b16f3e7346a0bf6e5cfc71f6080c6475ff75a0fce78172a58e4f8ece8f73ab47385ffd57d3001a
|
@@ -0,0 +1,43 @@
|
|
1
|
+
version: 2
|
2
|
+
|
3
|
+
jobs:
|
4
|
+
build:
|
5
|
+
parallelism: 3 # run three instances of this job in parallel
|
6
|
+
docker:
|
7
|
+
- image: circleci/ruby:2.4.2-jessie-node
|
8
|
+
environment:
|
9
|
+
BUNDLE_JOBS: 3
|
10
|
+
BUNDLE_RETRY: 3
|
11
|
+
BUNDLE_PATH: vendor/bundle
|
12
|
+
steps:
|
13
|
+
- checkout
|
14
|
+
|
15
|
+
- run:
|
16
|
+
name: Which bundler?
|
17
|
+
command: bundle -v
|
18
|
+
|
19
|
+
- restore_cache:
|
20
|
+
keys:
|
21
|
+
- sift-bundle-{{ checksum "sift.gemspec" }}
|
22
|
+
- sift-bundle-
|
23
|
+
|
24
|
+
- run:
|
25
|
+
name: Bundle Install
|
26
|
+
command: bundle check || bundle install
|
27
|
+
|
28
|
+
- save_cache:
|
29
|
+
key: sift-bundle-{{ checksum "sift.gemspec" }}
|
30
|
+
paths:
|
31
|
+
- vendor/bundle
|
32
|
+
|
33
|
+
- run:
|
34
|
+
name: Run rspec in parallel
|
35
|
+
command: |
|
36
|
+
bundle exec rspec --profile 10 \
|
37
|
+
--format RspecJunitFormatter \
|
38
|
+
--out test_results/rspec.xml \
|
39
|
+
--format progress \
|
40
|
+
$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
41
|
+
|
42
|
+
- store_test_results:
|
43
|
+
path: test_results
|
data/HISTORY
CHANGED
@@ -1,3 +1,91 @@
|
|
1
|
+
=== 4.0.0 2019-05-15
|
2
|
+
- Breaking change: Propagate exception in Client.track() – previously we were silently swallowing exceptions and now we are bubbling them up. You will need to add exception handling code.
|
3
|
+
- Fix URL encoding
|
4
|
+
- Add Circle build
|
5
|
+
|
6
|
+
=== 3.3.0 2018-07-31
|
7
|
+
- Add support for rescore_user and get_user_score APIs
|
8
|
+
|
9
|
+
=== 3.2.0 2018-07-05
|
10
|
+
- Add new query parameter force_workflow_run
|
11
|
+
|
12
|
+
=== 3.1.0 2018-06-04
|
13
|
+
- Adds support for get session decisions to [Decisions API](https://siftscience.com/developers/docs/curl/decisions-api)
|
14
|
+
|
15
|
+
=== 3.0.1 2018-04-06
|
16
|
+
- Improved documentation on HISTORY and README.MD
|
17
|
+
|
18
|
+
=== 3.0.0 2018-03-05
|
19
|
+
- Adds support for Sift Science API Version 205, including new [`$create_content`](https://siftscience.com/developers/docs/curl/events-api/reserved-events/create-content) and [`$update_content`](https://siftscience.com/developers/docs/curl/events-api/reserved-events/update-content) formats
|
20
|
+
- V205 APIs are now called -- **this is an incompatible change**
|
21
|
+
- (use `:version => 204` to call the previous API version)
|
22
|
+
- Adds support for content decisions to [Decisions API](https://siftscience.com/developers/docs/curl/decisions-api)
|
23
|
+
|
24
|
+
INCOMPATIBLE CHANGES INTRODUCED IN API V205:
|
25
|
+
- `$create_content` and `$update_content` have significantly changed, and the old format will be rejected
|
26
|
+
- `$send_message` and `$submit_review` events are no longer valid
|
27
|
+
- V205 improves server-side event data validation. In V204 and earlier, server-side validation accepted some events that did not conform to the published APIs in our [developer documentation](https://siftscience.com/developers/docs/curl/events-api). V205 does not modify existing event APIs other than those mentioned above, but may reject invalid event data that were previously accepted. **Please test your integration on V205 in sandbox before using in production.**
|
28
|
+
|
29
|
+
=== 2.2.1.0 2018-02-12
|
30
|
+
* Add session level decisions in Apply Decisions APIs.
|
31
|
+
|
32
|
+
=== 2.0.0.0 2016-07-19
|
33
|
+
* adds support for v204 of Sift Science's APIs
|
34
|
+
* adds Workflow Status API, User Decisions API, Order Decisions API
|
35
|
+
* v204 APIs are now called by default -- this is an incompatible change
|
36
|
+
(use :version => 203 to call the previous API version)
|
37
|
+
* uses Hash arg for optional params in Client methods -- incompatible change
|
38
|
+
|
39
|
+
=== 1.1.7.2 2015-04-13
|
40
|
+
* Fixed backwards compatibility issue
|
41
|
+
|
42
|
+
=== 1.1.7.0 2015-02-24
|
43
|
+
* Added Unlabel functionality
|
44
|
+
|
45
|
+
=== 1.1.6.2 2014-09-19
|
46
|
+
* added API key parameter to track and label functions
|
47
|
+
|
48
|
+
=== 1.1.6.0 2014-09-03
|
49
|
+
* added module scoped API key variable
|
50
|
+
|
51
|
+
=== 1.1.4 2014-01-02
|
52
|
+
* removed support for ruby 1.9.2
|
53
|
+
* track/label return nil on failure
|
54
|
+
|
55
|
+
=== 1.1.3 2013-12-10
|
56
|
+
* nil values are removed from JSON body sent to track/label now.
|
57
|
+
* relaxed multi_json requirement to 1.0 or newer
|
58
|
+
* relaxed httparty requirement to 0.11.0 or newer
|
59
|
+
* migrated from fakeweb to webmock 1.16.0 or newer
|
60
|
+
|
61
|
+
=== 1.1.1 2013-11-14
|
62
|
+
* score request now requires API key
|
63
|
+
|
64
|
+
=== 1.1.0 2013-11-08
|
65
|
+
* now uses v203 API endpoint by default
|
66
|
+
|
67
|
+
=== 1.0.13 2014-10-22
|
68
|
+
* added path parameter to track function
|
69
|
+
* added label function for applying labels
|
70
|
+
* now requires httparty 0.12.0 or newer
|
71
|
+
* now requires multi_json 1.8.2 or newer
|
72
|
+
* now requires rspec 2.14.1 or newer for compilation only
|
73
|
+
|
74
|
+
=== 1.0.12 2013-06-13
|
75
|
+
* added score function for getting user scores.
|
76
|
+
* now requires httparty 0.10.0 or newer
|
77
|
+
* added rspec 2.0 or newer and rake dependency
|
78
|
+
|
79
|
+
=== 1.0.10 2013-01-09
|
80
|
+
* Add configurable path variable to Client
|
81
|
+
|
82
|
+
=== 1.0.5 2012-07-20
|
83
|
+
|
84
|
+
=== 1.0.3 2012-05-05
|
85
|
+
|
86
|
+
=== 1.0.2 2012-05-03
|
87
|
+
|
88
|
+
=== 1.0.1 2012-05-02
|
1
89
|
|
2
90
|
=== 1.0 2012-05-02
|
3
91
|
* Initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 Sift Science
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
# Sift Ruby bindings
|
2
|
+
|
3
|
+
[![CircleCI](https://circleci.com/gh/SiftScience/sift-ruby.svg?style=svg)](https://circleci.com/gh/SiftScience/sift-ruby)
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* Ruby 2.0.0 or above.
|
8
|
+
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
If you want to build the gem from source:
|
13
|
+
|
14
|
+
```
|
15
|
+
$ gem build sift.gemspec
|
16
|
+
```
|
17
|
+
|
18
|
+
Alternatively, you can install the gem from rubygems.org:
|
19
|
+
|
20
|
+
```
|
21
|
+
gem install sift
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
### Creating a Client:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require "sift"
|
30
|
+
|
31
|
+
Sift.api_key = '<your_api_key_here>'
|
32
|
+
Sift.account_id = '<your_account_id_here>'
|
33
|
+
client = Sift::Client.new()
|
34
|
+
|
35
|
+
##### OR
|
36
|
+
|
37
|
+
client = Sift::Client.new(api_key: '<your_api_key_here>', account_id: '<your_account_id_here>')
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
### Sending a transaction event
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
event = "$transaction"
|
45
|
+
|
46
|
+
user_id = "23056" # User ID's may only contain a-z, A-Z, 0-9, =, ., -, _, +, @, :, &, ^, %, !, $
|
47
|
+
|
48
|
+
properties = {
|
49
|
+
"$user_id" => user_id,
|
50
|
+
"$user_email" => "buyer@gmail.com",
|
51
|
+
"$seller_user_id" => "2371",
|
52
|
+
"seller_user_email" => "seller@gmail.com",
|
53
|
+
"$transaction_id" => "573050",
|
54
|
+
"$payment_method" => {
|
55
|
+
"$payment_type" => "$credit_card",
|
56
|
+
"$payment_gateway" => "$braintree",
|
57
|
+
"$card_bin" => "542486",
|
58
|
+
"$card_last4" => "4444"
|
59
|
+
},
|
60
|
+
"$currency_code" => "USD",
|
61
|
+
"$amount" => 15230000,
|
62
|
+
}
|
63
|
+
|
64
|
+
response = client.track(event, properties)
|
65
|
+
|
66
|
+
response.ok? # returns true or false
|
67
|
+
response.body # API response body
|
68
|
+
response.http_status_code # HTTP response code, 200 is ok.
|
69
|
+
response.api_status # status field in the return body, Link to Error Codes
|
70
|
+
response.api_error_message # Error message associated with status Error Code
|
71
|
+
|
72
|
+
# Request a score for the user with user_id 23056
|
73
|
+
response = client.score(user_id)
|
74
|
+
```
|
75
|
+
|
76
|
+
## Decisions
|
77
|
+
|
78
|
+
To learn more about the decisions endpoint visit our [developer docs](https://sift.com/developers/docs/ruby/decisions-api/get-decisions).
|
79
|
+
|
80
|
+
### List of Configured Decisions
|
81
|
+
|
82
|
+
Get a list of your decisions.
|
83
|
+
|
84
|
+
**Optional Params**
|
85
|
+
- `entity_type`: `:user` or `:order` or `:session` or `:content`
|
86
|
+
- `abuse_types`: `["payment_abuse", "content_abuse", "content_abuse",
|
87
|
+
"account_abuse", "legacy", "account_takeover"]`
|
88
|
+
|
89
|
+
**Returns**
|
90
|
+
|
91
|
+
A `Response` object
|
92
|
+
|
93
|
+
**Example:**
|
94
|
+
```ruby
|
95
|
+
# fetch a list of all your decisions
|
96
|
+
response = client.decisions({
|
97
|
+
entity_type: :user,
|
98
|
+
abuse_types: ["payment_abuse", "content_abuse"]
|
99
|
+
})
|
100
|
+
|
101
|
+
# Check that response is okay.
|
102
|
+
unless response.ok?
|
103
|
+
raise "Unable to fetch decisions #{response.api_error_message} " +
|
104
|
+
"#{response.api_error_description}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# find a decisions with the id "block_bad_user"
|
108
|
+
user_decision = response.body["data"].find do |decision|
|
109
|
+
decision["id"] == "block_bad_user"
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get the next page
|
113
|
+
|
114
|
+
if response.body["has_more"]
|
115
|
+
client.decisions(response.body)
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
|
120
|
+
### Apply a decision
|
121
|
+
|
122
|
+
Applies a decision to an entity. Visit our [developer docs](http://sift.com/developers/docs/ruby/decisions-api/apply-decision) for more information.
|
123
|
+
|
124
|
+
**Required Params:**
|
125
|
+
- `decision_id`, `source`, `user_id`
|
126
|
+
|
127
|
+
**Other Params**
|
128
|
+
- `order_id`: when applying a decision to an order, you must pass in the `order_id`
|
129
|
+
- `session_id`: when applying a decision to a session, you must pass in the `session_id`
|
130
|
+
- `analyst`: when `source` is set to `manual_review`, this field *is required*
|
131
|
+
|
132
|
+
**Returns**
|
133
|
+
`Response` object.
|
134
|
+
|
135
|
+
**Examples:**
|
136
|
+
```ruby
|
137
|
+
# apply decision to a user
|
138
|
+
response = client.apply_decision({
|
139
|
+
decision_id: "block_bad_user",
|
140
|
+
source: "manual_review",
|
141
|
+
analyst: "bob@your_company.com",
|
142
|
+
user_id: "john@example.com"
|
143
|
+
})
|
144
|
+
|
145
|
+
# apply decision to "john@example.com"'s order
|
146
|
+
response = client.apply_decision({
|
147
|
+
decision_id: "block_bad_order",
|
148
|
+
source: "manual_review",
|
149
|
+
analyst: "bob@your_company.com",
|
150
|
+
user_id: "john@example.com",
|
151
|
+
order_id: "ORDER_1234"
|
152
|
+
})
|
153
|
+
|
154
|
+
# apply decision to "john@example.com"'s session
|
155
|
+
response = client.apply_decision({
|
156
|
+
decision_id: "block_bad_session",
|
157
|
+
source: "manual_review",
|
158
|
+
analyst: "bob@your_company.com",
|
159
|
+
user_id: "john@example.com",
|
160
|
+
session_id: "SESSION_ID_1234"
|
161
|
+
})
|
162
|
+
|
163
|
+
# apply decision to "john@example.com"'s content
|
164
|
+
response = client.apply_decision({
|
165
|
+
decision_id: "block_bad_session",
|
166
|
+
source: "manual_review",
|
167
|
+
analyst: "bob@your_company.com",
|
168
|
+
user_id: "john@example.com",
|
169
|
+
content_id: "CONTENT_ID_1234"
|
170
|
+
})
|
171
|
+
|
172
|
+
|
173
|
+
# Make sure you handle the response after applying a decision:
|
174
|
+
|
175
|
+
if response.ok?
|
176
|
+
# do stuff
|
177
|
+
else
|
178
|
+
# Error message
|
179
|
+
response.api_error_message
|
180
|
+
|
181
|
+
# Summary of the error
|
182
|
+
response.api_error_description
|
183
|
+
|
184
|
+
# hash of errors:
|
185
|
+
# key: field in question
|
186
|
+
# value: description of the issue
|
187
|
+
response.api_error_issues
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
## Sending a Label
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
# Label the user with user_id 23056 as Bad with all optional fields
|
195
|
+
response = client.label(user_id, {
|
196
|
+
"$is_bad" => true,
|
197
|
+
"$abuse_type" => "payment_abuse",
|
198
|
+
"$description" => "Chargeback issued",
|
199
|
+
"$source" => "Manual Review",
|
200
|
+
"$analyst" => "analyst.name@your_domain.com"
|
201
|
+
})
|
202
|
+
|
203
|
+
# Get the status of a workflow run
|
204
|
+
response = client.get_workflow_status('my_run_id')
|
205
|
+
|
206
|
+
# Get the latest decisions for a user
|
207
|
+
response = client.get_user_decisions('example_user_id')
|
208
|
+
|
209
|
+
# Get the latest decisions for an order
|
210
|
+
response = client.get_order_decisions('example_order_id')
|
211
|
+
|
212
|
+
# Get the latest decisions for a session
|
213
|
+
response = client.get_session_decisions('example_user_id', 'example_session_id')
|
214
|
+
|
215
|
+
# Get the latest decisions for an content
|
216
|
+
response = client.get_content_decisions('example_user_id', 'example_order_id')
|
217
|
+
```
|
218
|
+
|
219
|
+
## Response Object
|
220
|
+
|
221
|
+
All requests to our apis will return a `Response` instance.
|
222
|
+
|
223
|
+
### Public Methods:
|
224
|
+
- `ok?` returns `true` when the response is a `200`-`299`, `false` if it isn't
|
225
|
+
- `body` returns a hash representation of the json body returned.
|
226
|
+
- `api_error_message` returns a string describing the api error code.
|
227
|
+
- `api_error_description` a summary of the error that occured.
|
228
|
+
- `api_error_issues` a hash describing the items the error occured. The `key` is the item and the `value` is the description of the error.
|
229
|
+
|
230
|
+
|
231
|
+
## Building
|
232
|
+
|
233
|
+
Building and publishing the gem is captured by the following steps:
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
$ gem build sift.gemspec
|
237
|
+
$ gem push sift-<current version>.gem
|
238
|
+
|
239
|
+
$ bundle
|
240
|
+
$ rake -T
|
241
|
+
$ rake build
|
242
|
+
$ rake install
|
243
|
+
$ rake release
|
244
|
+
```
|
245
|
+
|
246
|
+
|
247
|
+
## Testing
|
248
|
+
|
249
|
+
To run the various tests use the rake command as follows:
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
$ rake spec
|
253
|
+
```
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "multi_json"
|
2
|
+
|
3
|
+
require_relative "../../validate/decision"
|
4
|
+
require_relative "../../client"
|
5
|
+
require_relative "../../router"
|
6
|
+
require_relative "../../utils/hash_getter"
|
7
|
+
|
8
|
+
module Sift
|
9
|
+
class Client
|
10
|
+
class Decision
|
11
|
+
class ApplyTo
|
12
|
+
PROPERTIES = %w{
|
13
|
+
source
|
14
|
+
analyst
|
15
|
+
description
|
16
|
+
order_id
|
17
|
+
session_id
|
18
|
+
content_id
|
19
|
+
user_id
|
20
|
+
account_id
|
21
|
+
time
|
22
|
+
}
|
23
|
+
|
24
|
+
attr_reader :decision_id, :configs, :getter, :api_key
|
25
|
+
|
26
|
+
PROPERTIES.each do |attribute|
|
27
|
+
class_eval %{
|
28
|
+
def #{attribute}
|
29
|
+
getter.get(:#{attribute})
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(api_key, decision_id, configs)
|
35
|
+
@api_key = api_key
|
36
|
+
@decision_id = decision_id
|
37
|
+
@configs = configs
|
38
|
+
@getter = Utils::HashGetter.new(configs)
|
39
|
+
end
|
40
|
+
|
41
|
+
def run
|
42
|
+
if errors.empty?
|
43
|
+
send_request
|
44
|
+
else
|
45
|
+
Response.new(
|
46
|
+
MultiJson.dump({
|
47
|
+
status: 55,
|
48
|
+
error_message: errors.join(", ")
|
49
|
+
}),
|
50
|
+
400,
|
51
|
+
nil
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def send_request
|
59
|
+
Router.post(path, {
|
60
|
+
body: request_body,
|
61
|
+
headers: headers
|
62
|
+
})
|
63
|
+
end
|
64
|
+
|
65
|
+
def request_body
|
66
|
+
{
|
67
|
+
source: source,
|
68
|
+
description: description,
|
69
|
+
analyst: analyst,
|
70
|
+
decision_id: decision_id,
|
71
|
+
time: time
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def errors
|
76
|
+
validator = Validate::Decision.new(configs)
|
77
|
+
|
78
|
+
if applying_to_order?
|
79
|
+
validator.valid_order?
|
80
|
+
elsif applying_to_session?
|
81
|
+
validator.valid_session?
|
82
|
+
else
|
83
|
+
validator.valid_user?
|
84
|
+
end
|
85
|
+
|
86
|
+
validator.error_messages
|
87
|
+
end
|
88
|
+
|
89
|
+
def applying_to_order?
|
90
|
+
configs.has_key?("order_id") || configs.has_key?(:order_id)
|
91
|
+
end
|
92
|
+
|
93
|
+
def applying_to_session?
|
94
|
+
configs.has_key?("session_id") || configs.has_key?(:session_id)
|
95
|
+
end
|
96
|
+
|
97
|
+
def applying_to_content?
|
98
|
+
configs.has_key?("content_id") || configs.has_key?(:content_id)
|
99
|
+
end
|
100
|
+
|
101
|
+
def path
|
102
|
+
if applying_to_order?
|
103
|
+
"#{user_path}/orders/#{CGI.escape(order_id)}/decisions"
|
104
|
+
elsif applying_to_session?
|
105
|
+
"#{user_path}/sessions/#{CGI.escape(session_id)}/decisions"
|
106
|
+
elsif applying_to_content?
|
107
|
+
"#{user_path}/content/#{CGI.escape(content_id)}/decisions"
|
108
|
+
else
|
109
|
+
"#{user_path}/decisions"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def user_path
|
114
|
+
"#{base_path}/users/#{CGI.escape(user_id)}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def base_path
|
118
|
+
"#{Client::API3_ENDPOINT}/v3/accounts/#{account_id}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def headers
|
122
|
+
{
|
123
|
+
"Content-type" => "application/json"
|
124
|
+
}.merge(Client.build_auth_header(api_key))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
require_relative "../router"
|
4
|
+
require_relative "../validate/decision"
|
5
|
+
require_relative "../utils/hash_getter"
|
6
|
+
require_relative "./decision/apply_to"
|
7
|
+
|
8
|
+
module Sift
|
9
|
+
class Client
|
10
|
+
class Decision
|
11
|
+
FILTER_PARAMS = %w{ limit entity_type abuse_types from }
|
12
|
+
|
13
|
+
attr_reader :account_id, :api_key
|
14
|
+
|
15
|
+
def initialize(api_key, account_id)
|
16
|
+
@account_id = account_id
|
17
|
+
@api_key = api_key
|
18
|
+
end
|
19
|
+
|
20
|
+
def list(options = {})
|
21
|
+
getter = Utils::HashGetter.new(options)
|
22
|
+
|
23
|
+
if path = getter.get(:next_ref)
|
24
|
+
request_next_page(path)
|
25
|
+
else
|
26
|
+
Router.get(index_path, {
|
27
|
+
query: build_query(getter),
|
28
|
+
headers: auth_header
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_query(getter)
|
34
|
+
FILTER_PARAMS.inject({}) do |result, filter|
|
35
|
+
if value = getter.get(filter)
|
36
|
+
result[filter] = value.is_a?(Array) ? value.join(",") : value
|
37
|
+
end
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def apply_to(configs = {})
|
44
|
+
getter = Utils::HashGetter.new(configs)
|
45
|
+
configs[:account_id] = account_id
|
46
|
+
|
47
|
+
ApplyTo.new(api_key, getter.get(:decision_id), configs).run
|
48
|
+
end
|
49
|
+
|
50
|
+
def index_path
|
51
|
+
"#{Client::API3_ENDPOINT}/v3/accounts/#{account_id}/decisions"
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def request_next_page(path)
|
57
|
+
Router.get(path, headers: auth_header)
|
58
|
+
end
|
59
|
+
|
60
|
+
def auth_header
|
61
|
+
Client.build_auth_header(api_key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|