customerio 3.1.0 → 4.0.1

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: 48f0d7c8bb61994c6bee0e1b846772f7ab304913182a1d1ac87f52a6e4e9beff
4
- data.tar.gz: e8df14b0db35439d08687a2ff61161d5d6bfc3a9f8ae6df71ba9c1cd7d4c91e9
3
+ metadata.gz: fbff37c21ea57a934d671356e89ef06114170d0b753c91048c255b399ce146de
4
+ data.tar.gz: 1d225801d24005870b63aa2f95850b47cef6ef822f7f3132ea9b7378cffaa852
5
5
  SHA512:
6
- metadata.gz: 7fff0a46a46e90a65f39694abf8713abe1a5e9edd0f388d26fea80d305332ed8425998397822899a9b66f27e77fb98e1051cd332842c73cd20da0a7ad7380a9d
7
- data.tar.gz: 1eab0fb3fe94024954b04f77c34029aa2b9a9b6a089d5d6aa86f9070101e0bf13e7019725e8031fcdd7af0ddf76532e4b2b85b6dfe7e482ecb5f407b339df381
6
+ metadata.gz: c41f22bc7fe6038432cd9e854c5bd18cd4b117f2320d02c3e142f5256cf0626de05e982db9676fdc3feed48cd26a6343e10717c196ab0e22b7d3798d4b5bb444
7
+ data.tar.gz: f70520dda7f7defab832cc4efc85771c10e3e042aff034512a261b630f73db2f63474b8103dbf43e4e98be29a0e03a20b0993f1a9e31871f84e2fad41d6d0f8c
@@ -1,6 +1,6 @@
1
1
  name: ruby_ci
2
2
 
3
- on: [push]
3
+ on: [push,pull_request]
4
4
 
5
5
  jobs:
6
6
  build:
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,13 @@
1
+ ## Customerio 4.0.1 - July 13, 2021
2
+ ### Changed
3
+ - Update addressable gem dependency to v2.8.0
4
+
5
+ ## Customerio 4.0.0 - July 6, 2021
6
+ ### Removed
7
+ - The `anonymous_track` method.
8
+
9
+ ### Added
10
+ - The `track_anonymous` method replaces `anonymous_track`. This method requires an `anonymous_id` parameter and will no longer trigger campaigns. If you previously used anonymous events to trigger campaigns, you can still do so [directly through the API](https://customer.io/docs/api/#operation/trackAnonymous). We now refer to anonymous events that trigger campaigns as ["invite events"](https://customer.io/docs/anonymous-events/#anonymous-or-invite).
1
11
 
2
12
  ## Customerio 3.1.0 - March 25, 2021
3
13
  ### Added
data/README.md CHANGED
@@ -131,10 +131,18 @@ $customerio.track(5, "purchase", :type => "socks", :price => "13.99", :timestamp
131
131
 
132
132
  ### Tracking anonymous events
133
133
 
134
- You can also send anonymous events, for situations where you don't yet have a customer record but still want to trigger a campaign:
134
+ You can also send anonymous events, for situations where you don't yet have a customer record yet. An anonymous event requires an `anonymous_id` representing the unknown person and an event `name`. When you identify a person, you can set their `anonymous_id` attribute. If [event merging](https://customer.io/docs/anonymous-events/#turn-on-merging) is turned on in your workspace, and the attribute matches the `anonymous_id` in one or more events that were logged within the last 30 days, we associate those events with the person.
135
+
136
+ Anonymous events cannot trigger campaigns by themselves. To trigger a campaign, the anonymous event must be associated with a person within 72 hours of the `track_anonymous` request.
135
137
 
136
138
  ```ruby
137
- $customerio.anonymous_track("help_enquiry", :recipient => 'user@example.com')
139
+ # Arguments
140
+ # anonymous_id (required) - the id representing the unknown person.
141
+ # name (required) - the name of the event you want to track.
142
+ # attributes (optional) - any related information you want to attach to the
143
+ # event.
144
+
145
+ $customerio.track_anonymous(anonymous_id, "product_view", :type => "socks" )
138
146
  ```
139
147
 
140
148
  Use the `recipient` attribute to specify the email address to send the messages to. [See our documentation on how to use anonymous events for more details](https://learn.customer.io/recipes/invite-emails.html).
data/customerio.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.version = Customerio::VERSION
18
18
 
19
19
  gem.add_dependency('multi_json', "~> 1.0")
20
- gem.add_dependency('addressable', '~> 2.7.0')
20
+ gem.add_dependency('addressable', '~> 2.8.0')
21
21
 
22
22
  gem.add_development_dependency('rake', '~> 10.5')
23
23
  gem.add_development_dependency('rspec', '3.3.0')
@@ -2,6 +2,12 @@ require "addressable/uri"
2
2
 
3
3
  module Customerio
4
4
  class Client
5
+ PUSH_OPENED = 'opened'
6
+ PUSH_CONVERTED = 'converted'
7
+ PUSH_DELIVERED = 'delivered'
8
+
9
+ VALID_PUSH_EVENTS = [PUSH_OPENED, PUSH_CONVERTED, PUSH_DELIVERED]
10
+
5
11
  class MissingIdAttributeError < RuntimeError; end
6
12
  class ParamError < RuntimeError; end
7
13
 
@@ -39,9 +45,11 @@ module Customerio
39
45
  create_customer_event(customer_id, event_name, attributes)
40
46
  end
41
47
 
42
- def anonymous_track(event_name, attributes = {})
48
+ def track_anonymous(anonymous_id, event_name, attributes = {})
49
+ raise ParamError.new("anonymous_id must be a non-empty string") if is_empty?(anonymous_id)
43
50
  raise ParamError.new("event_name must be a non-empty string") if is_empty?(event_name)
44
- create_anonymous_event(event_name, attributes)
51
+
52
+ create_anonymous_event(anonymous_id, event_name, attributes)
45
53
  end
46
54
 
47
55
  def add_device(customer_id, device_id, platform, data={})
@@ -70,6 +78,19 @@ module Customerio
70
78
  @client.request_and_verify_response(:delete, device_id_path(customer_id, device_id))
71
79
  end
72
80
 
81
+ def track_push_notification_event(event_name, attributes = {})
82
+ keys = [:delivery_id, :device_id, :timestamp]
83
+ attributes = Hash[attributes.map { |(k,v)| [ k.to_sym, v ] }].
84
+ select { |k, v| keys.include?(k) }
85
+
86
+ raise ParamError.new('event_name must be one of opened, converted, or delivered') unless VALID_PUSH_EVENTS.include?(event_name)
87
+ raise ParamError.new('delivery_id must be a non-empty string') unless attributes[:delivery_id] != "" and !attributes[:delivery_id].nil?
88
+ raise ParamError.new('device_id must be a non-empty string') unless attributes[:device_id] != "" and !attributes[:device_id].nil?
89
+ raise ParamError.new('timestamp must be a valid timestamp') unless valid_timestamp?(attributes[:timestamp])
90
+
91
+ @client.request_and_verify_response(:post, track_push_notification_event_path, attributes.merge(event: event_name))
92
+ end
93
+
73
94
  private
74
95
 
75
96
  def escape(val)
@@ -97,6 +118,10 @@ module Customerio
97
118
  "/api/v1/customers/#{escape(customer_id)}/unsuppress"
98
119
  end
99
120
 
121
+ def track_push_notification_event_path
122
+ "/push/events"
123
+ end
124
+
100
125
  def create_or_update(attributes = {})
101
126
  attributes = Hash[attributes.map { |(k,v)| [ k.to_sym, v ] }]
102
127
  raise MissingIdAttributeError.new("Must provide a customer id") if is_empty?(attributes[:id])
@@ -106,16 +131,27 @@ module Customerio
106
131
  end
107
132
 
108
133
  def create_customer_event(customer_id, event_name, attributes = {})
109
- create_event("#{customer_path(customer_id)}/events", event_name, attributes)
134
+ create_event(
135
+ url: "#{customer_path(customer_id)}/events",
136
+ event_name: event_name,
137
+ attributes: attributes
138
+ )
110
139
  end
111
140
 
112
- def create_anonymous_event(event_name, attributes = {})
113
- create_event("/api/v1/events", event_name, attributes)
141
+ def create_anonymous_event(anonymous_id, event_name, attributes = {})
142
+ create_event(
143
+ url: "/api/v1/events",
144
+ event_name: event_name,
145
+ anonymous_id: anonymous_id,
146
+ attributes: attributes
147
+ )
114
148
  end
115
149
 
116
- def create_event(url, event_name, attributes = {})
150
+ def create_event(url:, event_name:, anonymous_id: nil, attributes: {})
117
151
  body = { :name => event_name, :data => attributes }
118
152
  body[:timestamp] = attributes[:timestamp] if valid_timestamp?(attributes[:timestamp])
153
+ body[:anonymous_id] = anonymous_id unless anonymous_id.nil?
154
+
119
155
  @client.request_and_verify_response(:post, url, body)
120
156
  end
121
157
 
@@ -1,3 +1,3 @@
1
1
  module Customerio
2
- VERSION = "3.1.0"
2
+ VERSION = "4.0.1"
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -150,16 +150,18 @@ describe Customerio::Client do
150
150
  time = Time.now.to_i
151
151
 
152
152
  stub_request(:put, api_uri('/api/v1/customers/5')).with(
153
- body: json({
153
+ body: {
154
154
  id: 5,
155
155
  email: "customer@example.com",
156
156
  created_at: time,
157
157
  first_name: "Bob",
158
- plan: "basic"
159
- })).to_return(status: 200, body: "", headers: {})
158
+ plan: "basic",
159
+ anonymous_id: "anon-id"
160
+ }).to_return(status: 200, body: "", headers: {})
160
161
 
161
162
  client.identify({
162
163
  id: 5,
164
+ anonymous_id: "anon-id",
163
165
  email: "customer@example.com",
164
166
  created_at: time,
165
167
  first_name: "Bob",
@@ -381,31 +383,35 @@ describe Customerio::Client do
381
383
  end
382
384
 
383
385
  context "tracking an anonymous event" do
386
+ let(:anon_id) { "anon-id" }
387
+
384
388
  it "sends a POST request to the customer.io's anonymous event API" do
385
389
  stub_request(:post, api_uri('/api/v1/events')).
386
- with(body: json({ name: "purchase", data: {} })).
390
+ with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
387
391
  to_return(status: 200, body: "", headers: {})
388
392
 
389
- client.anonymous_track("purchase")
393
+ client.track_anonymous(anon_id, "purchase")
390
394
  end
391
395
 
392
396
  it "sends any optional event attributes" do
393
397
  stub_request(:post, api_uri('/api/v1/events')).
394
- with(body: json({
398
+ with(body: {
399
+ anonymous_id: anon_id,
395
400
  name: "purchase",
396
401
  data: {
397
402
  type: "socks",
398
403
  price: "13.99"
399
404
  }
400
- })).
405
+ }).
401
406
  to_return(status: 200, body: "", headers: {})
402
407
 
403
- client.anonymous_track("purchase", type: "socks", price: "13.99")
408
+ client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99")
404
409
  end
405
410
 
406
411
  it "allows sending of a timestamp" do
407
412
  stub_request(:post, api_uri('/api/v1/events')).
408
- with(body: json({
413
+ with(body: {
414
+ anonymous_id: anon_id,
409
415
  name: "purchase",
410
416
  data: {
411
417
  type: "socks",
@@ -413,73 +419,34 @@ describe Customerio::Client do
413
419
  timestamp: 1561231234
414
420
  },
415
421
  timestamp: 1561231234
416
- })).
422
+ }).
417
423
  to_return(status: 200, body: "", headers: {})
418
424
 
419
- client.anonymous_track("purchase", type: "socks", price: "13.99", timestamp: 1561231234)
425
+ client.track_anonymous(anon_id, "purchase", type: "socks", price: "13.99", timestamp: 1561231234)
420
426
  end
421
- end
422
- end
423
-
424
- describe "#anonymous_track" do
425
- it "raises an error if POST doesn't return a 2xx response code" do
426
- stub_request(:post, api_uri('/api/v1/events')).
427
- with(body: json(name: "purchase", data: {})).
428
- to_return(status: 500, body: "", headers: {})
429
-
430
- lambda { client.anonymous_track("purchase") }.should raise_error(Customerio::InvalidResponse)
431
- end
432
-
433
- it "throws an error when event_name is missing" do
434
- stub_request(:put, /track.customer.io/)
435
- .to_return(status: 200, body: "", headers: {})
436
-
437
- lambda { client.anonymous_track(" ") }.should raise_error(Customerio::Client::ParamError, "event_name must be a non-empty string")
438
- end
439
427
 
440
- it "uses the site_id and api key for basic auth and sends the event name" do
441
- stub_request(:post, api_uri('/api/v1/events')).
442
- with(body: json(name: "purchase", data: {})).
443
- to_return(status: 200, body: "", headers: {})
428
+ it "raises an error if POST doesn't return a 2xx response code" do
429
+ stub_request(:post, api_uri('/api/v1/events')).
430
+ with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
431
+ to_return(status: 500, body: "", headers: {})
444
432
 
445
- client.anonymous_track("purchase")
446
- end
447
-
448
- it "sends any optional event attributes" do
449
- stub_request(:post, api_uri('/api/v1/events')).
450
- with(body: {
451
- name: "purchase",
452
- data: {
453
- type: "socks",
454
- price: "27.99"
455
- },
456
- }).
457
-
458
- to_return(status: 200, body: "", headers: {})
459
-
460
- client.anonymous_track("purchase", type: "socks", price: "27.99")
461
- end
433
+ lambda { client.track_anonymous(anon_id, "purchase") }.should raise_error(Customerio::InvalidResponse)
434
+ end
462
435
 
463
- it "allows sending of a timestamp" do
464
- stub_request(:post, api_uri('/api/v1/events')).
465
- with(body: json({
466
- name: "purchase",
467
- data: {
468
- type: "socks",
469
- price: "27.99",
470
- timestamp: 1561235678
471
- },
472
- timestamp: 1561235678
473
- })).
436
+ it "throws an error when anonymous_id is missing" do
437
+ stub_request(:post, api_uri('/api/v1/events')).
438
+ with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
439
+ to_return(status: 500, body: "", headers: {})
474
440
 
475
- to_return(status: 200, body: "", headers: {})
441
+ lambda { client.track_anonymous("", "some_event") }.should raise_error(Customerio::Client::ParamError)
442
+ end
476
443
 
477
- client.anonymous_track("purchase", type: "socks", price: "27.99", timestamp: 1561235678)
478
- end
444
+ it "throws an error when event_name is missing" do
445
+ stub_request(:post, api_uri('/api/v1/events')).
446
+ with(body: { anonymous_id: anon_id, name: "purchase", data: {} }).
447
+ to_return(status: 500, body: "", headers: {})
479
448
 
480
- context "too many arguments are passed" do
481
- it "throws an error" do
482
- lambda { client.anonymous_track("purchase", "text", type: "socks", price: "27.99") }.should raise_error(ArgumentError)
449
+ lambda { client.track_anonymous(anon_id, "") }.should raise_error(Customerio::Client::ParamError)
483
450
  end
484
451
  end
485
452
  end
@@ -546,4 +513,83 @@ describe Customerio::Client do
546
513
  lambda { client.delete_device(5, nil) }.should raise_error(Customerio::Client::ParamError)
547
514
  end
548
515
  end
516
+
517
+ describe "#track_push_notification_event" do
518
+ attr_accessor :client, :attributes
519
+
520
+ before(:each) do
521
+ @client = Customerio::Client.new("SITE_ID", "API_KEY", :json => true)
522
+ @attributes = {
523
+ :delivery_id => 'foo',
524
+ :device_id => 'bar',
525
+ :timestamp => Time.now.to_i
526
+ }
527
+ end
528
+
529
+ it "sends a POST request to customer.io's /push/events endpoint" do
530
+ stub_request(:post, api_uri('/push/events')).
531
+ with(
532
+ :body => json(attributes.merge({
533
+ :event => 'opened'
534
+ })),
535
+ :headers => {
536
+ 'Content-Type' => 'application/json'
537
+ }).
538
+ to_return(:status => 200, :body => "", :headers => {})
539
+
540
+ client.track_push_notification_event('opened', attributes)
541
+ end
542
+
543
+ it "should raise if event is invalid" do
544
+ stub_request(:post, api_uri('/push/events')).
545
+ to_return(:status => 200, :body => "", :headers => {})
546
+
547
+ expect {
548
+ client.track_push_notification_event('closed', attributes.merge({ :delivery_id => nil }))
549
+ }.to raise_error(Customerio::Client::ParamError, 'event_name must be one of opened, converted, or delivered')
550
+ end
551
+
552
+ it "should raise if delivery_id is invalid" do
553
+ stub_request(:post, api_uri('/push/events')).
554
+ to_return(:status => 200, :body => "", :headers => {})
555
+
556
+ expect {
557
+ client.track_push_notification_event('opened', attributes.merge({ :delivery_id => nil }))
558
+ }.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
559
+
560
+ expect {
561
+ client.track_push_notification_event('opened', attributes.merge({ :delivery_id => '' }))
562
+ }.to raise_error(Customerio::Client::ParamError, 'delivery_id must be a non-empty string')
563
+ end
564
+
565
+ it "should raise if device_id is invalid" do
566
+ stub_request(:post, api_uri('/push/events')).
567
+ to_return(:status => 200, :body => "", :headers => {})
568
+
569
+ expect {
570
+ client.track_push_notification_event('opened', attributes.merge({ :device_id => nil }))
571
+ }.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
572
+
573
+ expect {
574
+ client.track_push_notification_event('opened', attributes.merge({ :device_id => '' }))
575
+ }.to raise_error(Customerio::Client::ParamError, 'device_id must be a non-empty string')
576
+ end
577
+
578
+ it "should raise if timestamp is invalid" do
579
+ stub_request(:post, api_uri('/push/events')).
580
+ to_return(:status => 200, :body => "", :headers => {})
581
+
582
+ expect {
583
+ client.track_push_notification_event('opened', attributes.merge({ :timestamp => nil }))
584
+ }.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
585
+
586
+ expect {
587
+ client.track_push_notification_event('opened', attributes.merge({ :timestamp => 999999999 }))
588
+ }.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
589
+
590
+ expect {
591
+ client.track_push_notification_event('opened', attributes.merge({ :timestamp => 100000000000 }))
592
+ }.to raise_error(Customerio::Client::ParamError, 'timestamp must be a valid timestamp')
593
+ end
594
+ end
549
595
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: customerio
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Allison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-25 00:00:00.000000000 Z
11
+ date: 2021-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.7.0
33
+ version: 2.8.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 2.7.0
40
+ version: 2.8.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -101,7 +101,6 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
- - ".circleci/config.yml"
105
104
  - ".github/workflows/main.yml"
106
105
  - ".gitignore"
107
106
  - CHANGELOG.markdown
@@ -141,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
140
  - !ruby/object:Gem::Version
142
141
  version: '0'
143
142
  requirements: []
144
- rubygems_version: 3.2.3
143
+ rubygems_version: 3.0.1
145
144
  signing_key:
146
145
  specification_version: 4
147
146
  summary: A ruby client for the Customer.io event API.
data/.circleci/config.yml DELETED
@@ -1,61 +0,0 @@
1
- ---
2
- version: 2
3
-
4
- references:
5
- restore_cache: &restore_cache
6
- type: cache-restore
7
- name: Restore bundle cache
8
- key: customerio-ruby-{{ checksum "customerio.gemspec" }}
9
-
10
- save_cache: &save_cache
11
- type: cache-save
12
- name: Store bundle cache
13
- key: customerio-ruby-{{ checksum "customerio.gemspec" }}
14
- paths:
15
- - vendor/bundle
16
-
17
- jobs:
18
- ruby_27:
19
- working_directory: ~/customerio-ruby
20
- docker:
21
- - image: circleci/ruby:2.7.2
22
- environment:
23
- RAILS_ENV: test
24
- steps:
25
- - checkout
26
- - *restore_cache
27
- - run: bundle install
28
- - *save_cache
29
- - run: bundle exec rspec
30
- ruby_26:
31
- working_directory: ~/customerio-ruby
32
- docker:
33
- - image: circleci/ruby:2.6.6
34
- environment:
35
- RAILS_ENV: test
36
- steps:
37
- - checkout
38
- - *restore_cache
39
- - run: bundle install
40
- - *save_cache
41
- - run: bundle exec rspec
42
- ruby_25:
43
- working_directory: ~/customerio-ruby
44
- docker:
45
- - image: circleci/ruby:2.5.8
46
- environment:
47
- RAILS_ENV: test
48
- steps:
49
- - checkout
50
- - *restore_cache
51
- - run: bundle install
52
- - *save_cache
53
- - run: bundle exec rspec
54
-
55
- workflows:
56
- version: 2
57
- test:
58
- jobs:
59
- - ruby_27
60
- - ruby_26
61
- - ruby_25