sift 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b20b0230176dc6340e5ea4939e51b6e1ed2642e788c25fa2f7f4e829b5c61ff
4
- data.tar.gz: 28932a0fddd658fe868c6c6b6b408ab1d8529060cfbe0766ffeef76e2398e43e
3
+ metadata.gz: cf4d6cd2e8ea54d5ea80fdca8b5668a1f86aa2639eaa1b69a105e8e81dd31222
4
+ data.tar.gz: cd087556fba6bbfd8269366fb8a7ae1c4727841a184056f09406a9c6d78658f5
5
5
  SHA512:
6
- metadata.gz: b905f6002c28777a4cf82cc6b0e59b2c79c300fdf1f4b4b3bf8b0bff8691946325d83794da812d5abc4b344b5e35d24f72b720aae1ddc0783b7e935117f35588
7
- data.tar.gz: e161d32f1c210f3fc4562b985537ceb6e2f304330a3fb14ddbce142cd105b0a0c567f6e177dd3c29c99e6c50133e3a7eb40c5ba922071914d9cf56b540c8f427
6
+ metadata.gz: 66a74c28328b082be3b0f492f0f001c998a7bc99bd95ede179a4c950974b332b4b55158cf418677ce4b904307464912f3248a56b200b88bb76038fd38cdff281
7
+ data.tar.gz: e6bb108cbcbf692266ff6d87a0a426476e8ad0a4523a2436a9f3d6f201ceeab63baad1121466e6a1ef7ec16df7135a577e59e532fe3d463ea47c6c7f47955576
data/.circleci/config.yml CHANGED
@@ -1,4 +1,40 @@
1
- version: 2
1
+ version: 2.1
2
+
3
+ orbs:
4
+ slack: circleci/slack@4.4.2
5
+
6
+ commands:
7
+ export_slack_id:
8
+ steps:
9
+ - run:
10
+ name : Exporting circleci username as slack id.
11
+ command: echo 'export SLACK_PARAM_MENTIONS="$CIRCLE_USERNAME"' >> "$BASH_ENV"
12
+ - run:
13
+ name : CircleCi To Slack user mapping.
14
+ command: |
15
+ echo $GITHUB_SLACK_USERMAPPING | base64 --decode > github_slack
16
+ while read -r line || [[ -n $line ]];
17
+ do
18
+ [[ ${line//[[:space:]]/} =~ ^#.* || -z "$line" ]] && continue
19
+ echo "$line" | tr "=" "\n" | while read -r key; do
20
+ read -r value
21
+ if [ "$CIRCLE_USERNAME" = "${key}" ]; then
22
+ echo "export SLACK_PARAM_MENTIONS='<@${value}>'" >> $BASH_ENV
23
+ fi
24
+ done
25
+ done < github_slack
26
+ rm github_slack
27
+
28
+ slack/notify: &slack_notify
29
+ branch_pattern: master
30
+ event: fail
31
+ channel: ci-build-status
32
+ template: SLACK_TAG_CI_FAILURE_TEMPLATE
33
+
34
+ context: &context
35
+ - slack-templates
36
+ - slack_Oauth
37
+ - Github_Slack_UserMapping
2
38
 
3
39
  jobs:
4
40
  build:
@@ -11,6 +47,7 @@ jobs:
11
47
  BUNDLE_PATH: vendor/bundle
12
48
  steps:
13
49
  - checkout
50
+ - export_slack_id
14
51
 
15
52
  - run:
16
53
  name: Which bundler?
@@ -41,3 +78,11 @@ jobs:
41
78
 
42
79
  - store_test_results:
43
80
  path: test_results
81
+ - slack/notify:
82
+ <<: *slack_notify
83
+
84
+ workflows:
85
+ ruby-test:
86
+ jobs:
87
+ - build:
88
+ context: *context
@@ -0,0 +1,12 @@
1
+ ## Purpose
2
+
3
+ ## Summary
4
+
5
+ ## Testing
6
+
7
+ ## Checklist
8
+ - [ ] The change was thoroughly tested manually
9
+ - [ ] The change was covered with unit tests
10
+ - [ ] The change was tested with real API calls (if applicable)
11
+ - [ ] Necessary changes were made in the integration tests (if applicable)
12
+ - [ ] New functionality is reflected in README
data/HISTORY CHANGED
@@ -1,3 +1,7 @@
1
+ === 4.2.0 2023-06-20
2
+ - Verification API support [Verification API](https://sift.com/developers/docs/curl/verification-api/overview)
3
+ - Support for score percentiles (only applicable for the accounts with the feature enabled)
4
+
1
5
  === 4.1.0 2022-06-22
2
6
  - Add return_route_info query param
3
7
 
@@ -0,0 +1,47 @@
1
+ require "sift"
2
+ require 'multi_json'
3
+
4
+ #$api_key = "put-a-valid-apikey"
5
+ #$user_id = "put-a-valid-userid"
6
+
7
+ def valid_send_properties
8
+ {
9
+ :$user_id => $user_id,
10
+ :$send_to => $user_id,
11
+ :$verification_type => '$email',
12
+ :$brand_name => 'all',
13
+ :$language => 'en',
14
+ :$event => {
15
+ :$session_id => 'gigtleqddo84l8cm15qe4il',
16
+ :$verified_event => '$login',
17
+ :$reason => '$automated_rule',
18
+ :$ip => '192.168.1.1',
19
+ :$browser => {
20
+ :$user_agent => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
21
+ }
22
+ }
23
+ }
24
+ end
25
+
26
+ def valid_resend_properties
27
+ {
28
+ :$user_id => $user_id,
29
+ :$verified_event => '$login'
30
+ }
31
+ end
32
+
33
+ def valid_check_properties
34
+ {
35
+ :$user_id => $user_id,
36
+ :$code => '668316'
37
+ }
38
+ end
39
+
40
+ #response = Sift::Client.new(:api_key => $api_key,:user_id => $user_id,:version=>1.1).verification_send(valid_send_properties)
41
+
42
+ #response = Sift::Client.new(:api_key => $api_key,:user_id => $user_id,:version=>1.1).verification_resend(valid_resend_properties)
43
+ response = Sift::Client.new(:api_key => $api_key,:user_id => $user_id,:version=>1.1).verification_check(valid_check_properties)
44
+
45
+ p response
46
+
47
+ puts "completed"
data/lib/sift/client.rb CHANGED
@@ -219,6 +219,7 @@ module Sift
219
219
  return_route_info = opts[:return_route_info]
220
220
  force_workflow_run = opts[:force_workflow_run]
221
221
  abuse_types = opts[:abuse_types]
222
+ include_score_percentiles = opts[:include_score_percentiles]
222
223
 
223
224
  raise("event must be a non-empty string") if (!event.is_a? String) || event.empty?
224
225
  raise("properties cannot be empty") if properties.empty?
@@ -231,6 +232,9 @@ module Sift
231
232
  query["return_route_info"] = "true" if return_route_info
232
233
  query["force_workflow_run"] = "true" if force_workflow_run
233
234
  query["abuse_types"] = abuse_types.join(",") if abuse_types
235
+ if include_score_percentiles == "true"
236
+ query["fields"] = "SCORE_PERCENTILES"
237
+ end
234
238
 
235
239
  options = {
236
240
  :body => MultiJson.dump(delete_nils(properties).merge({"$type" => event,
@@ -716,6 +720,71 @@ module Sift
716
720
  handle_response(apply_decision(configs))
717
721
  end
718
722
 
723
+ def build_default_headers_post(api_key)
724
+ {
725
+ "Authorization" => "Basic #{Base64.encode64(api_key+":")}",
726
+ "User-Agent" => "SiftScience/v#{@version} sift-ruby/#{VERSION}",
727
+ "Content-Type" => "application/json"
728
+ }
729
+ end
730
+
731
+ def verification_send(properties = {}, opts = {})
732
+ api_key = opts[:api_key] || @api_key
733
+ version = opts[:version] || @version
734
+ timeout = opts[:timeout] || @timeout
735
+
736
+ raise("properties cannot be empty") if properties.empty?
737
+ raise("api_key cannot be empty") if api_key.empty?
738
+
739
+
740
+ options = {
741
+ :body => MultiJson.dump(delete_nils(properties)),
742
+ :headers => build_default_headers_post(api_key)
743
+ }
744
+ options.merge!(:timeout => timeout) unless timeout.nil?
745
+
746
+ response = self.class.post(Sift.verification_api_send_path(@version), options)
747
+ Response.new(response.body, response.code, response.response)
748
+ end
749
+
750
+ def verification_resend(properties = {}, opts = {})
751
+ api_key = opts[:api_key] || @api_key
752
+ version = opts[:version] || @version
753
+ timeout = opts[:timeout] || @timeout
754
+
755
+ raise("properties cannot be empty") if properties.empty?
756
+ raise("api_key cannot be empty") if api_key.empty?
757
+
758
+
759
+ options = {
760
+ :body => MultiJson.dump(delete_nils(properties)),
761
+ :headers => build_default_headers_post(api_key)
762
+ }
763
+ options.merge!(:timeout => timeout) unless timeout.nil?
764
+
765
+ response = self.class.post(Sift.verification_api_resend_path(@version), options)
766
+ Response.new(response.body, response.code, response.response)
767
+ end
768
+
769
+ def verification_check(properties = {}, opts = {})
770
+ api_key = opts[:api_key] || @api_key
771
+ version = opts[:version] || @version
772
+ timeout = opts[:timeout] || @timeout
773
+
774
+ raise("properties cannot be empty") if properties.empty?
775
+ raise("api_key cannot be empty") if api_key.empty?
776
+
777
+
778
+ options = {
779
+ :body => MultiJson.dump(delete_nils(properties)),
780
+ :headers => build_default_headers_post(api_key)
781
+ }
782
+ options.merge!(:timeout => timeout) unless timeout.nil?
783
+
784
+ response = self.class.post(Sift.verification_api_check_path(@version), options)
785
+ Response.new(response.body, response.code, response.response)
786
+ end
787
+
719
788
  private
720
789
 
721
790
  def handle_response(response)
data/lib/sift/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Sift
2
- VERSION = "4.1.0"
2
+ VERSION = "4.2.0"
3
3
  API_VERSION = "205"
4
4
  end
data/lib/sift.rb CHANGED
@@ -9,6 +9,21 @@ module Sift
9
9
  "/v#{version}/events"
10
10
  end
11
11
 
12
+ # Returns the path for the specified API version
13
+ def self.verification_api_send_path(version=API_VERSION)
14
+ "/v#{version}/verification/send"
15
+ end
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
+
12
27
  # Returns the Score API path for the specified user ID and API version
13
28
  def self.score_api_path(user_id, version=API_VERSION)
14
29
  "/v#{version}/score/#{ERB::Util.url_encode(user_id)}/"
@@ -0,0 +1,117 @@
1
+ require_relative '../spec_helper'
2
+ require 'sift'
3
+
4
+ describe Sift::Client do
5
+
6
+ before :each do
7
+ Sift.api_key = nil
8
+ end
9
+
10
+ def valid_transaction_properties
11
+ {
12
+ :$type => "$add_item_to_cart",
13
+ :$user_id => "haneeshv@exalture.com",
14
+ :$session_id => "gigtleqddo84l8cm15qe4il",
15
+ :$item => {
16
+ :$item_id => "B004834GQO",
17
+ :$product_title => "The Slanket Blanket-Texas Tea",
18
+ :$price => 39990000,
19
+ :$currency_code => "USD",
20
+ :$upc => "6786211451001",
21
+ :$sku => "004834GQ",
22
+ :$brand => "Slanket",
23
+ :$manufacturer => "Slanket",
24
+ :$category => "Blankets & Throws",
25
+ :$tags => [
26
+ "Awesome",
27
+ "Wintertime specials"
28
+ ],
29
+ :$color => "Texas Tea",
30
+ :$quantity => 16
31
+ },
32
+ :$brand_name => "sift",
33
+ :$site_domain => "sift.com",
34
+ :$site_country => "US",
35
+ :$browser => {
36
+ :$user_agent => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
37
+ :$accept_language => "en-US",
38
+ :$content_language => "en-GB"
39
+ }
40
+ }
41
+ end
42
+
43
+ def percentile_response_json
44
+ {
45
+ :user_id => 'haneeshv@exalture.com',
46
+ :latest_labels => {},
47
+ :workflow_statuses => [],
48
+ :scores => {
49
+ :account_abuse => {
50
+ :score => 0.32787917675535705,
51
+ :reasons => [{
52
+ :name => 'Latest item product title',
53
+ :value => 'The Slanket Blanket-Texas Tea'
54
+ }],
55
+ :percentiles => {
56
+ :last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
57
+ }
58
+ },
59
+ :acontent_abuse => {
60
+ :score => 0.28056292905897995,
61
+ :reasons => [{
62
+ :name => 'timeSinceFirstEvent',
63
+ :value => '13.15 minutes'
64
+ }],
65
+ :percentiles => {
66
+ :last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
67
+ }
68
+ },
69
+ :payment_abuse => {
70
+ :score => 0.28610507028376797,
71
+ :reasons => [{
72
+ :name => 'Latest item currency code',
73
+ :value => 'USD'
74
+ }, {
75
+ :name => 'Latest item item ID',
76
+ :value => 'B004834GQO'
77
+ }, {
78
+ :name => 'Latest item product title',
79
+ :value => 'The Slanket Blanket-Texas Tea'
80
+ }],
81
+ :percentiles => {
82
+ :last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
83
+ }
84
+ },
85
+ :promotion_abuse => {
86
+ :score => 0.05731508921450917,
87
+ :percentiles => {
88
+ :last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
89
+ }
90
+ }
91
+ },
92
+ :status => 0,
93
+ :error_message => 'OK'
94
+ }
95
+ end
96
+
97
+ it "Successfully submits a v205 event with SCORE_PERCENTILES" do
98
+ response_json =
99
+ { :status => 0, :error_message => "OK", :score_response => percentile_response_json}
100
+ stub_request(:post, "https://api.siftscience.com/v205/events?fields=SCORE_PERCENTILES&return_score=true").
101
+ with { | request|
102
+ parsed_body = JSON.parse(request.body)
103
+ expect(parsed_body).to include("$api_key" => "overridden")
104
+ }.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
105
+
106
+ api_key = "foobar"
107
+ event = "$transaction"
108
+ properties = valid_transaction_properties
109
+
110
+ response = Sift::Client.new(:api_key => api_key, :version => "205")
111
+ .track(event, properties, :api_key => "overridden", :include_score_percentiles => "true", :return_score => "true")
112
+ expect(response.ok?).to eq(true)
113
+ expect(response.api_status).to eq(0)
114
+ expect(response.api_error_message).to eq("OK")
115
+ expect(response.body["score_response"]["scores"]["account_abuse"]["percentiles"]["last_7_days"]).to eq(-1.0)
116
+ end
117
+ end
@@ -0,0 +1,91 @@
1
+ require_relative "../spec_helper"
2
+ require "sift"
3
+
4
+ describe Sift::Client do
5
+
6
+ before :each do
7
+ Sift.api_key = nil
8
+ end
9
+
10
+ def valid_send_properties
11
+ {
12
+ :$user_id => 'billy_jones_301',
13
+ :$send_to => 'billy_jones_301@gmail.com',
14
+ :$verification_type => '$email',
15
+ :$brand_name => 'MyTopBrand',
16
+ :$language => 'en',
17
+ :$event => {
18
+ :$session_id => '09f7f361575d11ff',
19
+ :$verified_event => '$login',
20
+ :$reason => '$automated_rule',
21
+ :$ip => '192.168.1.1',
22
+ :$browser => {
23
+ :$user_agent => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
24
+ }
25
+ }
26
+ }
27
+ end
28
+
29
+ def valid_resend_properties
30
+ {
31
+ :$user_id => 'billy_jones_301',
32
+ :$verified_event => '$login'
33
+ }
34
+ end
35
+
36
+ def valid_check_properties
37
+ {
38
+ :$user_id => 'billy_jones_301',
39
+ :$code => '123456'
40
+ }
41
+ end
42
+
43
+ it "Successfully calls send" do
44
+ api_key = "foobar1"
45
+ user_id = "foobar2"
46
+
47
+ response_json = { :status => 0, :error_message => "OK"}
48
+
49
+ stub_request(:post, "https://foobar1:@api.siftscience.com/v1.1/verification/send")
50
+ .to_return(:status => 200, :body => MultiJson.dump(response_json))
51
+
52
+ response = Sift::Client.new(:api_key => api_key,:user_id => user_id,:version=>1.1).verification_send(valid_send_properties,:version => 205)
53
+ expect(response.ok?).to eq(true)
54
+ expect(response.api_status).to eq(0)
55
+ expect(response.api_error_message).to eq("OK")
56
+
57
+ end
58
+
59
+ it "Successfully calls resend" do
60
+ api_key = "foobar1"
61
+ user_id = "foobar2"
62
+
63
+ response_json = { :status => 0, :error_message => "OK"}
64
+
65
+ stub_request(:post, "https://foobar1:@api.siftscience.com/v1.1/verification/resend")
66
+ .to_return(:status => 200, :body => MultiJson.dump(response_json))
67
+
68
+ response = Sift::Client.new(:api_key => api_key,:user_id => user_id,:version=>1.1).verification_resend(valid_resend_properties,:version => 205)
69
+ expect(response.ok?).to eq(true)
70
+ expect(response.api_status).to eq(0)
71
+ expect(response.api_error_message).to eq("OK")
72
+
73
+ end
74
+
75
+ it "Successfully calls check" do
76
+ api_key = "foobar1"
77
+ user_id = "foobar2"
78
+
79
+ response_json = { :status => 0, :error_message => "OK"}
80
+
81
+ stub_request(:post, "https://foobar1:@api.siftscience.com/v1.1/verification/check")
82
+ .to_return(:status => 200, :body => MultiJson.dump(response_json))
83
+
84
+ response = Sift::Client.new(:api_key => api_key,:user_id => user_id,:version=>1.1).verification_check(valid_check_properties,:version => 205)
85
+ expect(response.ok?).to eq(true)
86
+ expect(response.api_status).to eq(0)
87
+ expect(response.api_error_message).to eq("OK")
88
+
89
+ end
90
+
91
+ end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sift
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Sadaghiani
8
8
  - Yoav Schatzberg
9
9
  - Jacob Burnim
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-07-11 00:00:00.000000000 Z
13
+ date: 2023-07-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -124,6 +124,7 @@ extensions: []
124
124
  extra_rdoc_files: []
125
125
  files:
126
126
  - ".circleci/config.yml"
127
+ - ".github/pull_request_template.md"
127
128
  - ".gitignore"
128
129
  - Gemfile
129
130
  - HISTORY
@@ -131,6 +132,7 @@ files:
131
132
  - README.md
132
133
  - Rakefile
133
134
  - examples/simple.rb
135
+ - examples/validation_apis.rb
134
136
  - lib/sift.rb
135
137
  - lib/sift/client.rb
136
138
  - lib/sift/client/decision.rb
@@ -148,15 +150,17 @@ files:
148
150
  - spec/unit/client/decision/apply_to_spec.rb
149
151
  - spec/unit/client/decision_spec.rb
150
152
  - spec/unit/client_203_spec.rb
153
+ - spec/unit/client_205_spec.rb
151
154
  - spec/unit/client_label_spec.rb
152
155
  - spec/unit/client_spec.rb
156
+ - spec/unit/client_validationapi_spec.rb
153
157
  - spec/unit/router_spec.rb
154
158
  - spec/unit/validate/decision_spec.rb
155
159
  - spec/unit/validate/primitive_spec.rb
156
160
  homepage: http://siftscience.com
157
161
  licenses: []
158
162
  metadata: {}
159
- post_install_message:
163
+ post_install_message:
160
164
  rdoc_options: []
161
165
  require_paths:
162
166
  - lib
@@ -171,8 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
175
  - !ruby/object:Gem::Version
172
176
  version: '0'
173
177
  requirements: []
174
- rubygems_version: 3.1.4
175
- signing_key:
178
+ rubygems_version: 3.0.3.1
179
+ signing_key:
176
180
  specification_version: 4
177
181
  summary: Sift Science Ruby API Gem
178
182
  test_files:
@@ -182,8 +186,10 @@ test_files:
182
186
  - spec/unit/client/decision/apply_to_spec.rb
183
187
  - spec/unit/client/decision_spec.rb
184
188
  - spec/unit/client_203_spec.rb
189
+ - spec/unit/client_205_spec.rb
185
190
  - spec/unit/client_label_spec.rb
186
191
  - spec/unit/client_spec.rb
192
+ - spec/unit/client_validationapi_spec.rb
187
193
  - spec/unit/router_spec.rb
188
194
  - spec/unit/validate/decision_spec.rb
189
195
  - spec/unit/validate/primitive_spec.rb