userlist 0.7.2 → 0.8.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: ee5f47b48e2bcc0babdbb7bcc85e84e5b197dacefb777eb19764d6f23e78e682
4
- data.tar.gz: 53caac6db3e462e9fe280541a7249da39e821a6a8bed7c70373131bebe9a6e19
3
+ metadata.gz: 4d6e93ef4ff51c272a689c07261fd423941a7244bec1cedf84af7207cd702816
4
+ data.tar.gz: 6c424b3183ec05af8a620dd39dea582bd097fc1514e800f8cd2b63aab342b90f
5
5
  SHA512:
6
- metadata.gz: 687b4ff1d89c5c98814fc89fe7cb8097577bd0cea63138f40e194eb47d6d6a2807b624c9dd15f2b64868f0473f1baaf268b6f7cb3945b713c20d00150b71739c
7
- data.tar.gz: 0b72bc8a28a6cba596c5afaff369e62b26cc8a84347f0059f68859c02df270562663c9e7faa8ddbb89a7053cf6d811d7dfcafa75f2f9233c27a36aebd72e4b4a
6
+ metadata.gz: f8ef2403697c2a9369f0b74737a5429cd0f650c4c22f1e09ab18d024dc7750622032077eb1fb392611ee1fa1907ea48b8e2d2aad2afbf6246fe3eb96c7f2fddd
7
+ data.tar.gz: e2578be25dd0be0db2d721d900f14910f238a72554918319ecad8ba16d3fffaac5da982b6e4c306c4af6bc540f12baeea71c6e7a4e9a0c4418a150028cb38fee
@@ -5,14 +5,12 @@ jobs:
5
5
  strategy:
6
6
  matrix:
7
7
  ruby:
8
- - 2.4
9
- - 2.5
10
- - 2.6
11
- - 2.7
12
8
  - 3.0
9
+ - 3.1
10
+ - 3.2
13
11
  runs-on: ubuntu-latest
14
12
  steps:
15
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
16
14
  - uses: ruby/setup-ruby@v1
17
15
  with:
18
16
  ruby-version: ${{ matrix.ruby }}
data/.rubocop.yml CHANGED
@@ -51,6 +51,9 @@ Style/ClassAndModuleChildren:
51
51
  Layout/MultilineMethodCallIndentation:
52
52
  EnforcedStyle: indented
53
53
 
54
+ Layout/SpaceAroundOperators:
55
+ EnforcedStyleForExponentOperator: space
56
+
54
57
  Style/SymbolArray:
55
58
  Enabled: false
56
59
 
data/CHANGELOG.md ADDED
@@ -0,0 +1,84 @@
1
+ # Userlist for Ruby Changelog
2
+
3
+ ## v0.8.1 (2023-11-30)
4
+
5
+ - Fixes issue with customizability of push? and delete? methods on events and relationships
6
+
7
+ ## v0.8.0 (2023-08-02)
8
+
9
+ - Adds a ActiveJob push strategy
10
+ - Adds support for retries of failed requests
11
+ - Adds response logging to the push client
12
+ - Adds support for payloads on delete requests
13
+
14
+ ## v0.7.2 (2022-10-20)
15
+
16
+ - Improves connection handling between requests
17
+ - Improves handling of arguments passed to Sidekiq
18
+
19
+ ## v0.7.1 (2022-02-10)
20
+
21
+ - Fixes issue with Sidekiq payloads (#4)
22
+
23
+ ## v0.7.0 (2022-02-02)
24
+
25
+ - Allows users without an identifier but with an email address
26
+
27
+ ## v0.6.0 (2021-05-14)
28
+
29
+ - Automatically manage one side of the relationships
30
+ - Always requires a user and a company on relationships
31
+
32
+ ## v0.5.0 (2021-01-22)
33
+
34
+ - Adds support for relationships
35
+ - Adds support for company events
36
+ - Adds support for skipping certain operations
37
+ - Adds lazy lookup for push strategies
38
+ - Adds a Sidekiq push strategy
39
+ - Allow numerics as identifiers
40
+ - Improves Userlist::Token to work with more than just strings
41
+ - Improves the way resources are serialized
42
+ - Improves JSON serialization
43
+ - Replaces userlist.io with userlist.com
44
+ - Require at least Ruby 2.4
45
+
46
+ ## v0.4.1 (2020-03-16)
47
+
48
+ - Fixes a problem when configuring the client (#1)
49
+
50
+ ## v0.4.0 (2020-03-06)
51
+
52
+ - Adds improved error messages for configuration errors
53
+ - Adds support for user token generation
54
+ - Require at least Ruby 2.3
55
+
56
+ ## v0.3.0 (2019-06-27)
57
+
58
+ - Adds additional aliases for the create method
59
+ - Adds resource models for User, Company, and Event
60
+ - Adds a more flexible interface to the push client
61
+ - Adds more HTTP methods to the push client
62
+
63
+ ## v0.2.2 (2019-03-18)
64
+
65
+ - Adds support for Ruby 2.2
66
+
67
+ ## v0.2.1 (2019-03-13)
68
+
69
+ - Adds support for Ruby 2.3
70
+
71
+ ## v0.2.0 (2018-11-21)
72
+
73
+ - Adds the ability to adjust the configuration
74
+ - Adds convenience class methods to Userlist::Push
75
+ - Adds track and identify aliases for event and user push methods
76
+ - Adds null strategy that discards everything for testing purposes
77
+ - Adds logging support
78
+ - Adds threaded push strategy to deliver requests without blocking the main thread
79
+ - Adds Userlist::Push as a nicer interface to the push endpoint
80
+ - Require at least Ruby 2.1
81
+
82
+ ## v0.1.0 (2018-01-18)
83
+
84
+ - Initial release
data/Gemfile CHANGED
@@ -6,6 +6,8 @@ gemspec
6
6
 
7
7
  gem 'guard-rspec', '~> 4.7'
8
8
  gem 'guard-rubocop', '~> 1.3'
9
- gem 'rubocop', '~> 0.68'
9
+ gem 'rubocop', '~> 1.45'
10
10
 
11
11
  gem 'sidekiq'
12
+ gem 'activejob'
13
+ gem 'uri'
data/README.md CHANGED
@@ -44,15 +44,15 @@ end
44
44
 
45
45
  The possible configuration values are listed in the table below.
46
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 |
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`, `:active_job`, `: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
56
 
57
57
  ### Disabling in development and test environments
58
58
 
@@ -53,7 +53,7 @@ module Userlist
53
53
 
54
54
  def config_from_environment
55
55
  default_config.keys.each_with_object({}) do |key, config|
56
- value = ENV["USERLIST_#{key.to_s.upcase}"]
56
+ value = ENV.fetch("USERLIST_#{key.to_s.upcase}", nil)
57
57
  config[key] = value if value
58
58
  end
59
59
  end
@@ -27,8 +27,8 @@ module Userlist
27
27
  request(Net::HTTP::Put, endpoint, payload)
28
28
  end
29
29
 
30
- def delete(endpoint)
31
- request(Net::HTTP::Delete, endpoint)
30
+ def delete(endpoint, payload = nil)
31
+ request(Net::HTTP::Delete, endpoint, payload)
32
32
  end
33
33
 
34
34
  private
@@ -58,7 +58,11 @@ module Userlist
58
58
  logger.debug "Sending #{request.method} to #{URI.join(endpoint, request.path)} with body #{request.body}"
59
59
 
60
60
  http.start unless http.started?
61
- http.request(request)
61
+ response = http.request(request)
62
+
63
+ logger.debug "Recieved #{response.code} #{response.message} with body #{response.body}"
64
+
65
+ response
62
66
  end
63
67
 
64
68
  def endpoint
@@ -19,7 +19,7 @@ module Userlist
19
19
  end
20
20
 
21
21
  def push?
22
- (user.nil? || user.push?) && (company.nil? || company.push?)
22
+ super && (user.nil? || user.push?) && (company.nil? || company.push?)
23
23
  end
24
24
  end
25
25
  end
@@ -23,7 +23,7 @@ module Userlist
23
23
  end
24
24
 
25
25
  def push?
26
- user&.push? && company&.push?
26
+ super && user&.push? && company&.push?
27
27
  end
28
28
  end
29
29
  end
@@ -33,9 +33,9 @@ module Userlist
33
33
  relationships[name.to_sym] = { type: type }
34
34
 
35
35
  generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
36
- def #{name}
37
- #{type}.from_payload(payload[:#{name}], config)
38
- end
36
+ def #{name} # def company
37
+ #{type}.from_payload(payload[:#{name}], config) # Company.from_payload(payload[:company], config)
38
+ end # end
39
39
  RUBY
40
40
  end
41
41
 
@@ -43,11 +43,11 @@ module Userlist
43
43
  relationships[name.to_sym] = options
44
44
 
45
45
  generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
46
- def #{name}
47
- relationship = self.class.relationships[:#{name}]
48
-
49
- ResourceCollection.new(payload[:#{name}], relationship, self, config)
50
- end
46
+ def #{name} # def companies
47
+ relationship = self.class.relationships[:#{name}] # relationship = self.class.relationships[:companies]
48
+ #
49
+ ResourceCollection.new(payload[:#{name}], relationship, self, config) # ResourceCollection.new(payload[:companies], relationship, self, config)
50
+ end #
51
51
  RUBY
52
52
  end
53
53
 
@@ -0,0 +1,16 @@
1
+ require 'active_job'
2
+
3
+ module Userlist
4
+ class Push
5
+ module Strategies
6
+ class ActiveJob
7
+ class Worker < ::ActiveJob::Base
8
+ def perform(method, *args)
9
+ client = Userlist::Push::Client.new
10
+ client.public_send(method, *args)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ require 'active_job'
2
+
3
+ require 'userlist/push/strategies/active_job/worker'
4
+
5
+ module Userlist
6
+ class Push
7
+ module Strategies
8
+ class ActiveJob
9
+ def initialize(config = {})
10
+ @config = Userlist.config.merge(config)
11
+ end
12
+
13
+ def call(*args)
14
+ options = default_options.merge(self.options)
15
+
16
+ worker_name = options.delete(:class)
17
+ worker_class = Object.const_get(worker_name)
18
+ worker_class
19
+ .set(options)
20
+ .perform_later(*normalize(args))
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :config
26
+
27
+ def options
28
+ @options ||= begin
29
+ options = config.push_strategy_options || {}
30
+ options.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
31
+ end
32
+ end
33
+
34
+ def default_options
35
+ {
36
+ class: 'Userlist::Push::Strategies::ActiveJob::Worker',
37
+ queue: 'default'
38
+ }
39
+ end
40
+
41
+ def normalize(args)
42
+ JSON.parse(JSON.generate(args))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -7,7 +7,7 @@ module Userlist
7
7
  end
8
8
 
9
9
  def call(*args)
10
- client.public_send(*args)
10
+ retryable.attempt { client.public_send(*args) }
11
11
  end
12
12
 
13
13
  private
@@ -17,6 +17,14 @@ module Userlist
17
17
  def client
18
18
  @client ||= Userlist::Push::Client.new(config)
19
19
  end
20
+
21
+ def retryable
22
+ @retryable ||= Userlist::Retryable.new do |response|
23
+ status = response.code.to_i
24
+
25
+ status >= 500 || status == 429
26
+ end
27
+ end
20
28
  end
21
29
  end
22
30
  end
@@ -22,7 +22,7 @@ module Userlist
22
22
  method, *args = *queue.pop
23
23
  break if method == :stop
24
24
 
25
- client.public_send(method, *args)
25
+ retryable.attempt { client.public_send(method, *args) }
26
26
  rescue StandardError => e
27
27
  logger.error "Failed to deliver payload: [#{e.class.name}] #{e.message}"
28
28
  end
@@ -44,6 +44,14 @@ module Userlist
44
44
  def client
45
45
  @client ||= Userlist::Push::Client.new(config)
46
46
  end
47
+
48
+ def retryable
49
+ @retryable ||= Userlist::Retryable.new do |response|
50
+ status = response.code.to_i
51
+
52
+ status >= 500 || status == 429
53
+ end
54
+ end
47
55
  end
48
56
  end
49
57
  end
@@ -12,13 +12,16 @@ module Userlist
12
12
  return strategy unless strategy.is_a?(Symbol) || strategy.is_a?(String)
13
13
 
14
14
  require_strategy(strategy)
15
- const_get(strategy.to_s.capitalize, false)
15
+
16
+ class_name = classify_strategy(strategy)
17
+ const_get(class_name, false)
16
18
  end
17
19
 
18
20
  def self.strategy_defined?(strategy)
19
21
  return true unless strategy.is_a?(Symbol) || strategy.is_a?(String)
20
22
 
21
- const_defined?(strategy.to_s.capitalize, false)
23
+ class_name = classify_strategy(strategy)
24
+ const_defined?(class_name, false)
22
25
  end
23
26
 
24
27
  def self.require_strategy(strategy)
@@ -26,6 +29,11 @@ module Userlist
26
29
 
27
30
  require("userlist/push/strategies/#{strategy}") unless strategy_defined?(strategy)
28
31
  end
32
+
33
+ def self.classify_strategy(strategy)
34
+ strategy.to_s.split('_').map(&:capitalize).join
35
+ end
36
+ private_class_method :classify_strategy
29
37
  end
30
38
  end
31
39
  end
@@ -0,0 +1,49 @@
1
+ module Userlist
2
+ class Retryable
3
+ include Userlist::Logging
4
+
5
+ RETRIES = 10
6
+ DELAY = 100
7
+ MULTIPLIER = 2
8
+ MAX_DELAY = 10_000
9
+
10
+ def initialize(retries: RETRIES, delay: DELAY, max_delay: MAX_DELAY, multiplier: MULTIPLIER, &retry_check)
11
+ @retries = retries
12
+ @delay = delay
13
+ @max_delay = max_delay
14
+ @multiplier = multiplier
15
+ @retry_check = retry_check
16
+ end
17
+
18
+ def retry?(value)
19
+ @retry_check.call(value)
20
+ end
21
+
22
+ def attempt
23
+ (0..@retries).each do |attempt|
24
+ if attempt.positive?
25
+ milliseconds = delay(attempt)
26
+ logger.debug "Retrying in #{milliseconds}ms, #{@retries - attempt} retries left"
27
+ sleep(milliseconds / 1000.0)
28
+ end
29
+
30
+ result = yield
31
+
32
+ return result unless retry?(result)
33
+ end
34
+
35
+ logger.debug 'Retries exhausted, giving up'
36
+
37
+ nil
38
+ end
39
+
40
+ private
41
+
42
+ def delay(attempt)
43
+ [
44
+ @delay * (@multiplier ** attempt),
45
+ @max_delay
46
+ ].min
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Userlist
2
- VERSION = '0.7.2'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
data/lib/userlist.rb CHANGED
@@ -3,6 +3,7 @@ require 'logger'
3
3
  require 'userlist/version'
4
4
  require 'userlist/config'
5
5
  require 'userlist/logging'
6
+ require 'userlist/retryable'
6
7
  require 'userlist/push'
7
8
  require 'userlist/token'
8
9
 
data/userlist.gemspec CHANGED
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency 'bundler', '>= 1.15'
25
25
  spec.add_development_dependency 'jwt', '~> 2.2'
26
- spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
27
  spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_development_dependency 'webmock', '~> 1.22'
28
+ spec.add_development_dependency 'webmock', '~> 3.18'
29
+
30
+ spec.metadata = { 'rubygems_mfa_required' => 'true' }
29
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: userlist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benedikt Deicke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-20 00:00:00.000000000 Z
11
+ date: 2023-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,20 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '12.3'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 12.3.3
47
+ version: '13.0'
51
48
  type: :development
52
49
  prerelease: false
53
50
  version_requirements: !ruby/object:Gem::Requirement
54
51
  requirements:
55
52
  - - "~>"
56
53
  - !ruby/object:Gem::Version
57
- version: '12.3'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 12.3.3
54
+ version: '13.0'
61
55
  - !ruby/object:Gem::Dependency
62
56
  name: rspec
63
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +72,14 @@ dependencies:
78
72
  requirements:
79
73
  - - "~>"
80
74
  - !ruby/object:Gem::Version
81
- version: '1.22'
75
+ version: '3.18'
82
76
  type: :development
83
77
  prerelease: false
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
- version: '1.22'
82
+ version: '3.18'
89
83
  description:
90
84
  email:
91
85
  - benedikt@userlist.com
@@ -97,6 +91,7 @@ files:
97
91
  - ".gitignore"
98
92
  - ".rspec"
99
93
  - ".rubocop.yml"
94
+ - CHANGELOG.md
100
95
  - CODE_OF_CONDUCT.md
101
96
  - Gemfile
102
97
  - Guardfile
@@ -120,6 +115,8 @@ files:
120
115
  - lib/userlist/push/resource_collection.rb
121
116
  - lib/userlist/push/serializer.rb
122
117
  - lib/userlist/push/strategies.rb
118
+ - lib/userlist/push/strategies/active_job.rb
119
+ - lib/userlist/push/strategies/active_job/worker.rb
123
120
  - lib/userlist/push/strategies/direct.rb
124
121
  - lib/userlist/push/strategies/null.rb
125
122
  - lib/userlist/push/strategies/sidekiq.rb
@@ -127,13 +124,15 @@ files:
127
124
  - lib/userlist/push/strategies/threaded.rb
128
125
  - lib/userlist/push/strategies/threaded/worker.rb
129
126
  - lib/userlist/push/user.rb
127
+ - lib/userlist/retryable.rb
130
128
  - lib/userlist/token.rb
131
129
  - lib/userlist/version.rb
132
130
  - userlist.gemspec
133
131
  homepage: http://github.com/userlistio/userlist-ruby
134
132
  licenses:
135
133
  - MIT
136
- metadata: {}
134
+ metadata:
135
+ rubygems_mfa_required: 'true'
137
136
  post_install_message:
138
137
  rdoc_options: []
139
138
  require_paths:
@@ -149,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
148
  - !ruby/object:Gem::Version
150
149
  version: '0'
151
150
  requirements: []
152
- rubygems_version: 3.3.7
151
+ rubygems_version: 3.4.21
153
152
  signing_key:
154
153
  specification_version: 4
155
154
  summary: Ruby wrapper for the Userlist API