userlist 0.2.2 → 0.6.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
- 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