userlist 0.2.2 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f6f2d40e30040c90510fd29c62e3b7738a323c11
4
- data.tar.gz: 3c4a710406464f67038df488ee9d796bb18fe220
2
+ SHA256:
3
+ metadata.gz: 1f8e5ee8f9d8d18f98ebc7744ced642b9641ec6bd156fff4fbf0352be37dbaa2
4
+ data.tar.gz: a532a136941e347e7c7dc454f3ec7a735990f53abd8ddaff1bdf50eb67a3c219
5
5
  SHA512:
6
- metadata.gz: 096e7606aa25d4bdfdb52b96e4f17d0a10fb187d087e90d21dc70c8acf24acf221657e0cf68f0983ed53831083116357279ca9a591a6f3d14de2e48f761c8020
7
- data.tar.gz: e6716c672ca4dd340dd57cc14c5a808e5af74630b5b18de48b8921167392418c5ece53d7f07a94f6535d3dc264ecd6ef11c3be6df7388d996055f99cf0a4c085
6
+ metadata.gz: 9065b7f9af8fc5692b334bcfa97410ee3260544f02cd6440cea57150d3daceb1e62c5b8fba8780f4309da764603966842b59064baad786918f1f23381a8ba0b5
7
+ data.tar.gz: f01918dafbaa9a837b25503f667b1387998036a5a626cce75fe3f45ef80539cb6e57aa9ab512bf8813f039b959eb138039ab0086bd98342dec5ef61f2d129969
@@ -0,0 +1,21 @@
1
+ name: Tests
2
+ on: [push]
3
+ jobs:
4
+ build:
5
+ strategy:
6
+ matrix:
7
+ ruby:
8
+ - 2.4
9
+ - 2.5
10
+ - 2.6
11
+ - 2.7
12
+ - 3.0
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v2
16
+ - uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ bundler-cache: true
20
+ - name: RSpec
21
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ /.env
data/.rubocop.yml CHANGED
@@ -1,10 +1,11 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.2
2
+ TargetRubyVersion: 2.4
3
+ NewCops: enable
3
4
  Exclude:
4
5
  - 'bin/*'
5
6
  - 'Guardfile'
6
7
 
7
- Metrics/LineLength:
8
+ Layout/LineLength:
8
9
  Enabled: false
9
10
 
10
11
  Metrics/ModuleLength:
@@ -32,13 +33,13 @@ Layout/ElseAlignment:
32
33
  Lint/AssignmentInCondition:
33
34
  Enabled: false
34
35
 
35
- Lint/EndAlignment:
36
+ Layout/EndAlignment:
36
37
  EnforcedStyleAlignWith: start_of_line
37
38
 
38
39
  Layout/AccessModifierIndentation:
39
40
  EnforcedStyle: outdent
40
41
 
41
- Layout/AlignParameters:
42
+ Layout/ParameterAlignment:
42
43
  EnforcedStyle: with_fixed_indentation
43
44
 
44
45
  Style/FrozenStringLiteralComment:
data/Gemfile CHANGED
@@ -6,3 +6,6 @@ gemspec
6
6
 
7
7
  gem 'guard-rspec', '~> 4.7'
8
8
  gem 'guard-rubocop', '~> 1.3'
9
+ gem 'rubocop', '~> 0.68'
10
+
11
+ gem 'sidekiq'
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Userlist
1
+ # Userlist for Ruby [![Build Status](https://github.com/userlist/userlist-ruby/workflows/Tests/badge.svg)](https://github.com/userlist/userlist-ruby)
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/userlist`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ This gem helps with integrating [Userlist](https://userlist.com) into Ruby applications.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ > To integrate Userlist into a Ruby on Rails application, please use [userlist-rails](https://github.com/userlist/userlist-rails)
6
6
 
7
7
  ## Installation
8
8
 
@@ -20,9 +20,180 @@ Or install it yourself as:
20
20
 
21
21
  $ gem install userlist
22
22
 
23
+ ## Configuration
24
+
25
+ The only required configuration is the Push API key. You can get your Push API key via the [Push API settings](https://app.userlist.com/settings/push) in your Userlist account.
26
+
27
+ Configuration values can either be set via the `Userlist.configure` method or as environment variables. The environment variables take precedence over configuration values from the initializer.
28
+
29
+ Configuration via environment variables:
30
+
31
+ ```shell
32
+ USERLIST_PUSH_KEY=VvB7pjDrv0V2hoaOCeZ5rIiUEPbEhSUN
33
+ USERLIST_PUSH_ID=6vPkJl44cm82y4aLBIzaOhuEHJd0Bm7b
34
+ ```
35
+
36
+ Configuration via an initializer:
37
+
38
+ ```ruby
39
+ Userlist.configure do |config|
40
+ config.push_key = 'VvB7pjDrv0V2hoaOCeZ5rIiUEPbEhSUN'
41
+ config.push_id = '6vPkJl44cm82y4aLBIzaOhuEHJd0Bm7b'
42
+ end
43
+ ```
44
+
45
+ The possible configuration values are listed in the table below.
46
+
47
+ | Name | Default value | Description |
48
+ | ----------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
49
+ | `push_key` | `nil` | The push key for your account. See [Push API settings](https://app.userlist.com/settings/push). |
50
+ | `push_id` | `nil` | The push id for your account. See [Push API settings](https://app.userlist.com/settings/push). |
51
+ | `push_endpoint` | `https://push.userlist.com/` | The HTTP endpoint that the library will send data to. |
52
+ | `push_strategy` | `:threaded` | The strategy to use to send data to the HTTP endpoint. Possible values are `:threaded`, `:sidekiq`, `:direct`, and `:null`. |
53
+ | `push_strategy_options` | `{}` | Any additional options for the push strategy. |
54
+ | `log_level` | `:warn` | The log level for Userlist related log messages. Possible values are `:debug`, `:error`, `:fatal`, `:info`, and `:warn` |
55
+ | `token_lifetime` | `3600` | The lifetime of generated in-app messages tokens in seconds |
56
+
57
+ ### Disabling in development and test environments
58
+
59
+ As sending test and development data into data into Userlist isn't very desirable, you can disable transmissions by setting the push strategy to `:null`.
60
+
61
+ ```ruby
62
+ Userlist.configure do |config|
63
+ config.push_strategy = :null
64
+ end
65
+ ```
66
+
23
67
  ## Usage
24
68
 
25
- TODO: Write usage instructions here
69
+ This library is a wrapper for Userlist's Push API. For details about the accepted payloads, please check [its documentation](https://userlist.com/docs/getting-started/integration-guide/).
70
+
71
+ ### Tracking Users
72
+
73
+ To manually send user data into Userlist, use the `Userlist::Push.users.push` method.
74
+
75
+ ```ruby
76
+ Userlist::Push.users.push(
77
+ identifier: 'user-1',
78
+ email: 'foo@example.com',
79
+ properties: {
80
+ first_name: 'Foo',
81
+ last_name: 'Example'
82
+ }
83
+ )
84
+ ```
85
+
86
+ It's also possible to delete a user from Userlist, using the `Userlist::Push.users.delete` method.
87
+
88
+ ```ruby
89
+ Userlist::Push.users.delete('user-1')
90
+ ```
91
+
92
+ ### Tracking Companies
93
+
94
+ To manually send company data into Userlist, use the `Userlist::Push.companies.push` method.
95
+
96
+ ```ruby
97
+ Userlist::Push.companies.push(
98
+ identifier: 'company-1',
99
+ email: 'Example, Inc.',
100
+ properties: {
101
+ industry: 'Software Testing'
102
+ }
103
+ )
104
+ ```
105
+
106
+ It's also possible to delete a user from Userlist, using the `Userlist::Push.companies.delete` method.
107
+
108
+ ```ruby
109
+ Userlist::Push.companies.delete('user-1')
110
+ ```
111
+
112
+ ### Tracking Relationships
113
+
114
+ Tracking relationships can either be done using nested properties in user or company payloads or via the `Userlist::Push.relationships.push` method.
115
+
116
+ ```ruby
117
+ Userlist::Push.relationships.push(
118
+ user: 'user-1',
119
+ company: 'company-1',
120
+ properties: {
121
+ role: 'owner'
122
+ }
123
+ )
124
+ ```
125
+
126
+ This is equivalent to specifying the relationship on the user model.
127
+
128
+ ```ruby
129
+ Userlist::Push.users.push(
130
+ identifier: 'user-1',
131
+ relationships: [
132
+ {
133
+ company: 'company-1',
134
+ properties: {
135
+ role: 'owner'
136
+ }
137
+ }
138
+ ]
139
+ )
140
+ ```
141
+
142
+ It's also equivalent specifying the relationship on the company model.
143
+
144
+ ```ruby
145
+ Userlist::Push.companies.push(
146
+ identifier: 'company-1',
147
+ relationships: [
148
+ {
149
+ user: 'user-1',
150
+ properties: {
151
+ role: 'owner'
152
+ }
153
+ }
154
+ ]
155
+ )
156
+ ```
157
+
158
+ ### Tracking Events
159
+
160
+ To track custom events use the `Userlist::Push.events.push` method.
161
+
162
+ ```ruby
163
+ Userlist::Push.events.push(
164
+ name: 'project_created',
165
+ user: 'user-1',
166
+ properties: {
167
+ project_name: 'Example project'
168
+ }
169
+ )
170
+ ```
171
+
172
+ Instead of just sending a user or company identifier, it's also possible to expand the properties into objects. This will update the user / company record as well as trigger the event in one operation.
173
+
174
+ ```ruby
175
+ Userlist::Push.events.push(
176
+ name: 'project_created',
177
+ user: {
178
+ identifier: 'user-1',
179
+ properties: {
180
+ projects: 5
181
+ }
182
+ },
183
+ properties: {
184
+ project_name: 'Example project'
185
+ }
186
+ )
187
+ ```
188
+
189
+ ### Tokens for in-app messages
190
+
191
+ In order to use in-app messages, you must create a JWT token for the currently signed in user on the server side. To do this, please configure both the `push_key` and the `push_id` configuration variables. Afterwards, you can use the `Userlist::Token.generate` method to get a signed token for the given user identifier.
192
+
193
+ ```ruby
194
+ Userlist::Token.generate('user-1')
195
+ # => "eyJraWQiOiI2dlBrSmw0NGNtODJ5NGFMQkl6YU9odU...kPGe8KX8JZBTQ"
196
+ ```
26
197
 
27
198
  ## Development
28
199
 
@@ -32,7 +203,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
203
 
33
204
  ## Contributing
34
205
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/userlist. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
206
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/userlist/userlist-ruby>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
207
 
37
208
  ## License
38
209
 
@@ -40,4 +211,12 @@ The gem is available as open source under the terms of the [MIT License](http://
40
211
 
41
212
  ## Code of Conduct
42
213
 
43
- Everyone interacting in the Userlist project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/userlist/blob/master/CODE_OF_CONDUCT.md).
214
+ Everyone interacting in the Userlist project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/userlist/userlist-ruby/blob/master/CODE_OF_CONDUCT.md).
215
+
216
+ ## What is Userlist?
217
+
218
+ [![Userlist](https://userlist.com/images/external/userlist-logo-github.svg)](https://userlist.com/)
219
+
220
+ [Userlist](https://userlist.com/) allows you to onboard and engage your SaaS users with targeted behavior-based campaigns using email or in-app messages.
221
+
222
+ Userlist was started in 2017 as an alternative to bulky enterprise messaging tools. We believe that running SaaS products should be more enjoyable. Learn more [about us](https://userlist.com/about-us/).
data/lib/userlist.rb CHANGED
@@ -4,8 +4,35 @@ require 'userlist/version'
4
4
  require 'userlist/config'
5
5
  require 'userlist/logging'
6
6
  require 'userlist/push'
7
+ require 'userlist/token'
7
8
 
8
9
  module Userlist
10
+ class Error < StandardError; end
11
+
12
+ class ArgumentError < Error; end
13
+
14
+ class ConfigurationError < Error
15
+ attr_reader :key
16
+
17
+ def initialize(key)
18
+ @key = key.to_sym
19
+
20
+ super <<~MESSAGE
21
+ Missing required configuration value for `#{key}`
22
+
23
+ Please set a value for `#{key}` using an environment variable:
24
+
25
+ USERLIST_#{key.to_s.upcase}=some-value-here
26
+
27
+ or via the `Userlist.configure` method:
28
+
29
+ Userlist.configure do |config|
30
+ config.#{key} = 'some-value-here'
31
+ end
32
+ MESSAGE
33
+ end
34
+ end
35
+
9
36
  class << self
10
37
  def config
11
38
  @config ||= Userlist::Config.new
@@ -13,7 +40,7 @@ module Userlist
13
40
 
14
41
  def logger
15
42
  @logger ||= begin
16
- logger = Logger.new(STDOUT)
43
+ logger = Logger.new($stdout)
17
44
  logger.progname = 'userlist'
18
45
  logger.level = Logger.const_get(config.log_level.to_s.upcase)
19
46
  logger
@@ -2,9 +2,12 @@ module Userlist
2
2
  class Config
3
3
  DEFAULT_CONFIGURATION = {
4
4
  push_key: nil,
5
- push_endpoint: 'https://push.userlist.io/',
5
+ push_id: nil,
6
+ push_endpoint: 'https://push.userlist.com/',
6
7
  push_strategy: :threaded,
7
- log_level: :warn
8
+ push_strategy_options: {},
9
+ log_level: :warn,
10
+ token_lifetime: 3600
8
11
  }.freeze
9
12
 
10
13
  def initialize(config_from_initialize = {})
@@ -36,6 +39,10 @@ module Userlist
36
39
  config == other.config && parent == other.parent
37
40
  end
38
41
 
42
+ def token_lifetime
43
+ self[:token_lifetime]&.to_i
44
+ end
45
+
39
46
  protected
40
47
 
41
48
  attr_reader :config, :parent
@@ -52,11 +59,11 @@ module Userlist
52
59
  end
53
60
 
54
61
  def key?(key)
55
- config.key?(key) || parent && parent.key?(key)
62
+ config.key?(key) || parent&.key?(key)
56
63
  end
57
64
 
58
65
  def [](key)
59
- config[key] || parent && parent[key]
66
+ config.key?(key) ? config[key] : parent && parent[key]
60
67
  end
61
68
 
62
69
  def []=(key, value)
data/lib/userlist/push.rb CHANGED
@@ -1,10 +1,24 @@
1
1
  require 'userlist/push/client'
2
2
  require 'userlist/push/strategies'
3
3
 
4
+ require 'userlist/push/resource'
5
+ require 'userlist/push/resource_collection'
6
+ require 'userlist/push/relation'
7
+
8
+ require 'userlist/push/operations/create'
9
+ require 'userlist/push/operations/delete'
10
+
11
+ require 'userlist/push/user'
12
+ require 'userlist/push/company'
13
+ require 'userlist/push/relationship'
14
+ require 'userlist/push/event'
15
+
16
+ require 'userlist/push/serializer'
17
+
4
18
  module Userlist
5
19
  class Push
6
20
  class << self
7
- [:event, :track, :user, :identify, :company].each do |method|
21
+ [:event, :track, :user, :identify, :company, :users, :events, :companies, :relationships].each do |method|
8
22
  define_method(method) { |*args| default_push_instance.send(method, *args) }
9
23
  end
10
24
 
@@ -15,53 +29,42 @@ module Userlist
15
29
  end
16
30
  end
17
31
 
18
- def initialize(config = {})
19
- @config = Userlist.config.merge(config)
20
- @mutex = Mutex.new
32
+ def initialize(configuration = {})
33
+ @config = Userlist.config.merge(configuration)
34
+ @strategy = Userlist::Push::Strategies.strategy_for(config.push_strategy, config)
21
35
  end
22
36
 
23
- def event(payload = {})
24
- with_mutex do
25
- raise ArgumentError, 'Missing required payload hash' unless payload
26
- raise ArgumentError, 'Missing required parameter :name' unless payload[:name]
27
- raise ArgumentError, 'Missing required parameter :user' unless payload[:user]
28
-
29
- payload[:occured_at] ||= Time.now
37
+ attr_reader :config, :strategy
30
38
 
31
- strategy.call(:post, '/events', payload)
32
- end
39
+ def events
40
+ @events ||= Relation.new(self, Event, [Operations::Create])
33
41
  end
34
- alias track event
35
-
36
- def user(payload = {})
37
- with_mutex do
38
- raise ArgumentError, 'Missing required payload hash' unless payload
39
- raise ArgumentError, 'Missing required parameter :identifier' unless payload[:identifier]
40
42
 
41
- strategy.call(:post, '/users', payload)
42
- end
43
+ def users
44
+ @users ||= Relation.new(self, User, [Operations::Create, Operations::Delete])
43
45
  end
44
- alias identify user
45
46
 
46
- def company(payload = {})
47
- with_mutex do
48
- raise ArgumentError, 'Missing required payload hash' unless payload
49
- raise ArgumentError, 'Missing required parameter :identifier' unless payload[:identifier]
50
-
51
- strategy.call(:post, '/companies', payload)
52
- end
47
+ def companies
48
+ @companies ||= Relation.new(self, Company, [Operations::Create, Operations::Delete])
53
49
  end
54
50
 
55
- private
51
+ def relationships
52
+ @relationships ||= Relation.new(self, Relationship, [Operations::Create, Operations::Delete])
53
+ end
56
54
 
57
- attr_reader :config
55
+ def event(payload = {})
56
+ events.create(payload)
57
+ end
58
58
 
59
- def strategy
60
- @strategy ||= Userlist::Push::Strategies.strategy_for(config.push_strategy, config)
59
+ def user(payload = {})
60
+ users.create(payload)
61
61
  end
62
62
 
63
- def with_mutex(&block)
64
- @mutex.synchronize(&block)
63
+ def company(payload = {})
64
+ companies.create(payload)
65
65
  end
66
+
67
+ alias track event
68
+ alias identify user
66
69
  end
67
70
  end