customerio 3.1.0 → 4.0.1

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 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