userlist 0.2.1 → 0.5.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 +4 -4
- data/.github/workflows/test.yml +21 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -4
- data/Gemfile +3 -0
- data/README.md +185 -6
- data/lib/userlist.rb +29 -2
- data/lib/userlist/config.rb +11 -4
- data/lib/userlist/push.rb +38 -35
- data/lib/userlist/push/client.rb +20 -5
- data/lib/userlist/push/company.rb +23 -0
- data/lib/userlist/push/event.rb +26 -0
- data/lib/userlist/push/operations/create.rb +25 -0
- data/lib/userlist/push/operations/delete.rb +23 -0
- data/lib/userlist/push/relation.rb +30 -0
- data/lib/userlist/push/relationship.rb +29 -0
- data/lib/userlist/push/resource.rb +119 -0
- data/lib/userlist/push/resource_collection.rb +21 -0
- data/lib/userlist/push/serializer.rb +64 -0
- data/lib/userlist/push/strategies.rb +20 -6
- data/lib/userlist/push/strategies/sidekiq.rb +37 -0
- data/lib/userlist/push/strategies/sidekiq/worker.rb +18 -0
- data/lib/userlist/push/strategies/threaded.rb +1 -1
- data/lib/userlist/push/strategies/threaded/worker.rb +4 -4
- data/lib/userlist/push/user.rb +19 -0
- data/lib/userlist/token.rb +68 -0
- data/lib/userlist/version.rb +1 -1
- data/userlist.gemspec +6 -5
- metadata +48 -15
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a76254952c47cc9014e31019550491b96b1a8f46814cb6e44750ddf4c4d966f1
|
4
|
+
data.tar.gz: 17eabd156ef0d1eda09a7480c9eb3f5822098f045123d2a2d9f33351630493d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d3311432655c8b7758d59733845558f526208874f31fee9034dbbb8a75bca653dc39b8b18007928b7fae7d2cf3efae449126c2c355bd6f3b3e5d0e82f2a24a7
|
7
|
+
data.tar.gz: 8531012b1ec1824c2ff60b537c641b17b534e60ea4665e476b66055f1f623ed51787c4a336402fb1adb63b1645e238008bb94ec64a2c7caf87cb21956d35111c
|
@@ -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
data/.rubocop.yml
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.4
|
3
|
+
NewCops: enable
|
3
4
|
Exclude:
|
4
5
|
- 'bin/*'
|
5
6
|
- 'Guardfile'
|
6
7
|
|
7
|
-
|
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
|
-
|
36
|
+
Layout/EndAlignment:
|
36
37
|
EnforcedStyleAlignWith: start_of_line
|
37
38
|
|
38
39
|
Layout/AccessModifierIndentation:
|
39
40
|
EnforcedStyle: outdent
|
40
41
|
|
41
|
-
Layout/
|
42
|
+
Layout/ParameterAlignment:
|
42
43
|
EnforcedStyle: with_fixed_indentation
|
43
44
|
|
44
45
|
Style/FrozenStringLiteralComment:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# Userlist
|
1
|
+
# Userlist for Ruby [](https://github.com/userlist/userlist-ruby)
|
2
2
|
|
3
|
-
|
3
|
+
This gem helps with integrating [Userlist](https://userlist.com) into Ruby applications.
|
4
4
|
|
5
|
-
|
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
|
-
|
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/
|
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/
|
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
|
+
[](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,9 +40,9 @@ module Userlist
|
|
13
40
|
|
14
41
|
def logger
|
15
42
|
@logger ||= begin
|
16
|
-
logger = Logger.new(
|
43
|
+
logger = Logger.new($stdout)
|
17
44
|
logger.progname = 'userlist'
|
18
|
-
logger.level = config.log_level
|
45
|
+
logger.level = Logger.const_get(config.log_level.to_s.upcase)
|
19
46
|
logger
|
20
47
|
end
|
21
48
|
end
|
data/lib/userlist/config.rb
CHANGED
@@ -2,9 +2,12 @@ module Userlist
|
|
2
2
|
class Config
|
3
3
|
DEFAULT_CONFIGURATION = {
|
4
4
|
push_key: nil,
|
5
|
-
|
5
|
+
push_id: nil,
|
6
|
+
push_endpoint: 'https://push.userlist.com/',
|
6
7
|
push_strategy: :threaded,
|
7
|
-
|
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
|
62
|
+
config.key?(key) || parent&.key?(key)
|
56
63
|
end
|
57
64
|
|
58
65
|
def [](key)
|
59
|
-
config[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(
|
19
|
-
@config = Userlist.config.merge(
|
20
|
-
@
|
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
|
-
|
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
|
-
|
32
|
-
|
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
|
-
|
42
|
-
|
43
|
+
def users
|
44
|
+
@users ||= Relation.new(self, User, [Operations::Create, Operations::Delete])
|
43
45
|
end
|
44
|
-
alias identify user
|
45
46
|
|
46
|
-
def
|
47
|
-
|
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
|
-
|
51
|
+
def relationships
|
52
|
+
@relationships ||= Relation.new(self, Relationship, [Operations::Create, Operations::Delete])
|
53
|
+
end
|
56
54
|
|
57
|
-
|
55
|
+
def event(payload = {})
|
56
|
+
events.create(payload)
|
57
|
+
end
|
58
58
|
|
59
|
-
def
|
60
|
-
|
59
|
+
def user(payload = {})
|
60
|
+
users.create(payload)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
64
|
-
|
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
|
data/lib/userlist/push/client.rb
CHANGED
@@ -10,10 +10,25 @@ module Userlist
|
|
10
10
|
|
11
11
|
def initialize(config = {})
|
12
12
|
@config = Userlist.config.merge(config)
|
13
|
+
|
14
|
+
raise Userlist::ConfigurationError, :push_key unless @config.push_key
|
15
|
+
raise Userlist::ConfigurationError, :push_endpoint unless @config.push_endpoint
|
16
|
+
end
|
17
|
+
|
18
|
+
def get(endpoint)
|
19
|
+
request(Net::HTTP::Get, endpoint)
|
20
|
+
end
|
21
|
+
|
22
|
+
def post(endpoint, payload = nil)
|
23
|
+
request(Net::HTTP::Post, endpoint, payload)
|
24
|
+
end
|
25
|
+
|
26
|
+
def put(endpoint, payload = nil)
|
27
|
+
request(Net::HTTP::Put, endpoint, payload)
|
13
28
|
end
|
14
29
|
|
15
|
-
def
|
16
|
-
request(
|
30
|
+
def delete(endpoint)
|
31
|
+
request(Net::HTTP::Delete, endpoint)
|
17
32
|
end
|
18
33
|
|
19
34
|
private
|
@@ -33,12 +48,12 @@ module Userlist
|
|
33
48
|
end
|
34
49
|
end
|
35
50
|
|
36
|
-
def request(path, payload =
|
37
|
-
request =
|
51
|
+
def request(method, path, payload = nil)
|
52
|
+
request = method.new(path)
|
38
53
|
request['Accept'] = 'application/json'
|
39
54
|
request['Authorization'] = "Push #{token}"
|
40
55
|
request['Content-Type'] = 'application/json; charset=UTF-8'
|
41
|
-
request.body = JSON.
|
56
|
+
request.body = JSON.generate(payload) if payload
|
42
57
|
|
43
58
|
logger.debug "Sending #{request.method} to #{URI.join(endpoint, request.path)} with body #{request.body}"
|
44
59
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Company < Resource
|
4
|
+
include Operations::Create
|
5
|
+
include Operations::Delete
|
6
|
+
|
7
|
+
def self.endpoint
|
8
|
+
'/companies'
|
9
|
+
end
|
10
|
+
|
11
|
+
has_many :relationships, type: 'Userlist::Push::Relationship'
|
12
|
+
has_many :users, type: 'Userlist::Push::User'
|
13
|
+
has_one :user, type: 'Userlist::Push::User'
|
14
|
+
|
15
|
+
def initialize(payload = {}, config = Userlist.config)
|
16
|
+
raise Userlist::ArgumentError, 'Missing required payload hash' unless payload
|
17
|
+
raise Userlist::ArgumentError, 'Missing required parameter :identifier' unless payload[:identifier]
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Event < Resource
|
4
|
+
include Operations::Create
|
5
|
+
|
6
|
+
has_one :user, type: 'Userlist::Push::User'
|
7
|
+
has_one :company, type: 'Userlist::Push::Company'
|
8
|
+
|
9
|
+
def initialize(payload = {}, config = Userlist.config)
|
10
|
+
raise Userlist::ArgumentError, 'Missing required payload' unless payload
|
11
|
+
raise Userlist::ArgumentError, 'Missing required parameter :name' unless payload[:name]
|
12
|
+
raise Userlist::ArgumentError, 'Missing required parameter :user or :company' unless payload[:user] || payload[:company]
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def occured_at
|
18
|
+
payload[:occured_at] || Time.now
|
19
|
+
end
|
20
|
+
|
21
|
+
def push?
|
22
|
+
(user.nil? || user.push?) && (company.nil? || company.push?)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
module Operations
|
4
|
+
module Create
|
5
|
+
module ClassMethods
|
6
|
+
def create(payload = {}, config = self.config)
|
7
|
+
return false unless resource = from_payload(payload, config)
|
8
|
+
|
9
|
+
strategy.call(:post, endpoint, resource) if resource.create?
|
10
|
+
end
|
11
|
+
|
12
|
+
alias push create
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend(ClassMethods)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create?
|
20
|
+
push?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
module Operations
|
4
|
+
module Delete
|
5
|
+
module ClassMethods
|
6
|
+
def delete(payload = {}, config = self.config)
|
7
|
+
return false unless resource = from_payload(payload, config)
|
8
|
+
|
9
|
+
strategy.call(:delete, resource.url) if resource.delete?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Relation
|
4
|
+
def initialize(scope, type, operations = [])
|
5
|
+
@scope = scope
|
6
|
+
@type = type
|
7
|
+
|
8
|
+
operations.each { |operation| singleton_class.send(:include, operation::ClassMethods) }
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :scope, :type
|
12
|
+
|
13
|
+
def from_payload(payload, config = self.config)
|
14
|
+
type.from_payload(payload, config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def endpoint
|
18
|
+
type.endpoint
|
19
|
+
end
|
20
|
+
|
21
|
+
def strategy
|
22
|
+
scope.strategy
|
23
|
+
end
|
24
|
+
|
25
|
+
def config
|
26
|
+
scope.config
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Relationship < Resource
|
4
|
+
include Operations::Create
|
5
|
+
include Operations::Delete
|
6
|
+
|
7
|
+
has_one :user, type: 'Userlist::Push::User'
|
8
|
+
has_one :company, type: 'Userlist::Push::Company'
|
9
|
+
|
10
|
+
def initialize(payload = {}, config = Userlist.config)
|
11
|
+
raise Userlist::ArgumentError, 'Missing required payload' unless payload
|
12
|
+
raise Userlist::ArgumentError, 'Missing required parameter :user or :company' unless payload[:user] || payload[:company]
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def url
|
18
|
+
raise Userlist::Error, "Cannot generate url for #{self.class.name} without a user" unless user
|
19
|
+
raise Userlist::Error, "Cannot generate url for #{self.class.name} without a company" unless company
|
20
|
+
|
21
|
+
"#{self.class.endpoint}/#{user.identifier}/#{company.identifier}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def push?
|
25
|
+
user&.push? && company&.push?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Resource
|
4
|
+
class << self
|
5
|
+
def resource_name
|
6
|
+
name.split('::')[-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def endpoint
|
10
|
+
"/#{resource_name.downcase}s"
|
11
|
+
end
|
12
|
+
|
13
|
+
def from_payload(payload, config = Userlist.config)
|
14
|
+
return payload if payload.nil?
|
15
|
+
return payload if payload.is_a?(self)
|
16
|
+
|
17
|
+
payload = { identifier: payload } if payload.is_a?(String) || payload.is_a?(Numeric)
|
18
|
+
|
19
|
+
new(payload, config)
|
20
|
+
end
|
21
|
+
|
22
|
+
def relationship_names
|
23
|
+
@relationship_names ||= Set.new
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def has_one(name, type:) # rubocop:disable Naming/PredicateName
|
29
|
+
relationship_names << name.to_sym
|
30
|
+
|
31
|
+
generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
32
|
+
def #{name}
|
33
|
+
#{type}.from_payload(payload[:#{name}], config)
|
34
|
+
end
|
35
|
+
RUBY
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_many(name, type:) # rubocop:disable Naming/PredicateName
|
39
|
+
relationship_names << name.to_sym
|
40
|
+
|
41
|
+
generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
42
|
+
def #{name}
|
43
|
+
ResourceCollection.new(payload[:#{name}], #{type}, config)
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def generated_methods
|
51
|
+
@generated_methods ||= Module.new.tap { |mod| include mod }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :payload, :config
|
56
|
+
|
57
|
+
def initialize(payload = {}, config = Userlist.config)
|
58
|
+
@payload = payload
|
59
|
+
@config = config
|
60
|
+
end
|
61
|
+
|
62
|
+
def respond_to_missing?(method, include_private = false)
|
63
|
+
attribute = method.to_s.sub(/=$/, '')
|
64
|
+
payload.key?(attribute.to_sym) || super
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_hash
|
68
|
+
Serializer.serialize(self)
|
69
|
+
end
|
70
|
+
alias to_h to_hash
|
71
|
+
|
72
|
+
def to_json(*args)
|
73
|
+
to_hash.to_json(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
def url
|
77
|
+
"#{self.class.endpoint}/#{identifier}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def identifier
|
81
|
+
payload[:identifier]
|
82
|
+
end
|
83
|
+
|
84
|
+
def hash
|
85
|
+
self.class.hash & payload.hash
|
86
|
+
end
|
87
|
+
|
88
|
+
def eql?(other)
|
89
|
+
hash == other.hash
|
90
|
+
end
|
91
|
+
alias == eql?
|
92
|
+
|
93
|
+
def attribute_names
|
94
|
+
payload.keys.map(&:to_sym) - relationship_names
|
95
|
+
end
|
96
|
+
|
97
|
+
def relationship_names
|
98
|
+
self.class.relationship_names.to_a
|
99
|
+
end
|
100
|
+
|
101
|
+
def push?
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def method_missing(method, *args, &block)
|
108
|
+
if method.to_s =~ /=$/
|
109
|
+
attribute = method.to_s.sub(/=$/, '')
|
110
|
+
payload[attribute.to_sym] = args.first
|
111
|
+
elsif payload.key?(method.to_sym)
|
112
|
+
payload[method.to_sym]
|
113
|
+
else
|
114
|
+
super
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class ResourceCollection
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :collection, :type, :config
|
7
|
+
|
8
|
+
def initialize(collection, type, config = Userlist.config)
|
9
|
+
@collection = Array(collection)
|
10
|
+
@type = type
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
collection.each do |resource|
|
16
|
+
yield type.from_payload(resource, config)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class Serializer
|
4
|
+
def self.serialize(resource)
|
5
|
+
new.serialize(resource)
|
6
|
+
end
|
7
|
+
|
8
|
+
def serialize(resource)
|
9
|
+
resource = serialize_resource(resource) if resource.is_a?(Userlist::Push::Resource)
|
10
|
+
resource
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def serialize_resource(resource)
|
16
|
+
return resource.identifier if serialized_resources.include?(resource)
|
17
|
+
|
18
|
+
serialized_resources << resource
|
19
|
+
|
20
|
+
return unless resource.push?
|
21
|
+
|
22
|
+
serialized = {}
|
23
|
+
|
24
|
+
resource.attribute_names.each do |name|
|
25
|
+
serialized[name] = resource.send(name)
|
26
|
+
end
|
27
|
+
|
28
|
+
resource.relationship_names.each do |name|
|
29
|
+
next unless result = serialize_relationship(resource.send(name))
|
30
|
+
|
31
|
+
serialized[name] = result
|
32
|
+
end
|
33
|
+
|
34
|
+
serialized
|
35
|
+
end
|
36
|
+
|
37
|
+
def serialize_relationship(relationship)
|
38
|
+
return unless relationship
|
39
|
+
|
40
|
+
case relationship
|
41
|
+
when Userlist::Push::ResourceCollection
|
42
|
+
serialize_collection(relationship)
|
43
|
+
when Userlist::Push::Resource
|
44
|
+
serialize_resource(relationship)
|
45
|
+
else
|
46
|
+
raise "Cannot serialize relationship type: #{relationship.class}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def serialize_collection(collection)
|
51
|
+
serialized = collection
|
52
|
+
.map(&method(:serialize_relationship))
|
53
|
+
.compact
|
54
|
+
.reject(&:empty?)
|
55
|
+
|
56
|
+
serialized unless serialized.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def serialized_resources
|
60
|
+
@serialized_resources ||= Set.new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,17 +1,31 @@
|
|
1
|
-
require 'userlist/push/strategies/null'
|
2
|
-
require 'userlist/push/strategies/direct'
|
3
|
-
require 'userlist/push/strategies/threaded'
|
4
|
-
|
5
1
|
module Userlist
|
6
2
|
class Push
|
7
3
|
module Strategies
|
8
4
|
def self.strategy_for(strategy, config = {})
|
9
|
-
strategy =
|
10
|
-
|
5
|
+
strategy = lookup_strategy(strategy)
|
11
6
|
strategy = strategy.new(config) if strategy.respond_to?(:new)
|
12
7
|
|
13
8
|
strategy
|
14
9
|
end
|
10
|
+
|
11
|
+
def self.lookup_strategy(strategy)
|
12
|
+
return strategy unless strategy.is_a?(Symbol) || strategy.is_a?(String)
|
13
|
+
|
14
|
+
require_strategy(strategy)
|
15
|
+
const_get(strategy.to_s.capitalize, false)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.strategy_defined?(strategy)
|
19
|
+
return true unless strategy.is_a?(Symbol) || strategy.is_a?(String)
|
20
|
+
|
21
|
+
const_defined?(strategy.to_s.capitalize, false)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.require_strategy(strategy)
|
25
|
+
return unless strategy.is_a?(Symbol) || strategy.is_a?(String)
|
26
|
+
|
27
|
+
require("userlist/push/strategies/#{strategy}") unless strategy_defined?(strategy)
|
28
|
+
end
|
15
29
|
end
|
16
30
|
end
|
17
31
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
require 'userlist/push/strategies/sidekiq/worker'
|
4
|
+
|
5
|
+
module Userlist
|
6
|
+
class Push
|
7
|
+
module Strategies
|
8
|
+
class Sidekiq
|
9
|
+
def initialize(config = {})
|
10
|
+
@config = Userlist.config.merge(config)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(*args)
|
14
|
+
::Sidekiq::Client.push(default_options.merge(options).merge('args' => args))
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :config
|
20
|
+
|
21
|
+
def options
|
22
|
+
@options ||= begin
|
23
|
+
options = config.push_strategy_options || {}
|
24
|
+
options.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_options
|
29
|
+
{
|
30
|
+
'class' => 'Userlist::Push::Strategies::Sidekiq::Worker',
|
31
|
+
'queue' => 'default'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
module Userlist
|
4
|
+
class Push
|
5
|
+
module Strategies
|
6
|
+
class Sidekiq
|
7
|
+
class Worker
|
8
|
+
include ::Sidekiq::Worker
|
9
|
+
|
10
|
+
def perform(method, *args)
|
11
|
+
client = Userlist::Push::Client.new
|
12
|
+
client.public_send(method, *args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -19,12 +19,12 @@ module Userlist
|
|
19
19
|
|
20
20
|
loop do
|
21
21
|
begin
|
22
|
-
method,
|
22
|
+
method, *args = *queue.pop
|
23
23
|
break if method == :stop
|
24
24
|
|
25
|
-
client.public_send(method,
|
26
|
-
rescue StandardError =>
|
27
|
-
logger.error "Failed to deliver payload: [#{
|
25
|
+
client.public_send(method, *args)
|
26
|
+
rescue StandardError => e
|
27
|
+
logger.error "Failed to deliver payload: [#{e.class.name}] #{e.message}"
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Push
|
3
|
+
class User < Resource
|
4
|
+
include Operations::Create
|
5
|
+
include Operations::Delete
|
6
|
+
|
7
|
+
has_many :relationships, type: 'Userlist::Push::Relationship'
|
8
|
+
has_many :companies, type: 'Userlist::Push::Company'
|
9
|
+
has_one :company, type: 'Userlist::Push::Company'
|
10
|
+
|
11
|
+
def initialize(payload = {}, config = Userlist.config)
|
12
|
+
raise Userlist::ArgumentError, 'Missing required payload' unless payload
|
13
|
+
raise Userlist::ArgumentError, 'Missing required parameter :identifier' unless payload[:identifier]
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Userlist
|
2
|
+
class Token
|
3
|
+
def self.generate(user, configuration = {})
|
4
|
+
config = Userlist.config.merge(configuration)
|
5
|
+
|
6
|
+
raise Userlist::ConfigurationError, :push_key unless config.push_key
|
7
|
+
raise Userlist::ConfigurationError, :push_id unless config.push_id
|
8
|
+
raise Userlist::ArgumentError, 'Missing required user or identifier' unless user
|
9
|
+
|
10
|
+
user = Userlist::Push::User.from_payload(user, config)
|
11
|
+
|
12
|
+
now = Time.now.utc.to_i
|
13
|
+
|
14
|
+
header = {
|
15
|
+
kid: config.push_id,
|
16
|
+
alg: 'HS256'
|
17
|
+
}
|
18
|
+
|
19
|
+
payload = {
|
20
|
+
sub: user.identifier,
|
21
|
+
exp: now + config.token_lifetime,
|
22
|
+
iat: now
|
23
|
+
}
|
24
|
+
|
25
|
+
new(payload: payload, header: header, key: config.push_key).to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(payload:, header:, key:, algorithm: 'HS256')
|
29
|
+
@payload = payload
|
30
|
+
@header = header
|
31
|
+
@algorithm = algorithm
|
32
|
+
@key = key
|
33
|
+
end
|
34
|
+
|
35
|
+
def encoded_header
|
36
|
+
encode(header)
|
37
|
+
end
|
38
|
+
|
39
|
+
def encoded_payload
|
40
|
+
encode(payload)
|
41
|
+
end
|
42
|
+
|
43
|
+
def encoded_header_and_payload
|
44
|
+
"#{encoded_header}.#{encoded_payload}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def signature
|
48
|
+
digest = OpenSSL::Digest.new(algorithm.sub('HS', 'SHA'))
|
49
|
+
signature = OpenSSL::HMAC.digest(digest, key, encoded_header_and_payload)
|
50
|
+
|
51
|
+
encode(signature)
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"#{encoded_header_and_payload}.#{signature}"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
attr_reader :payload, :header, :algorithm, :key
|
61
|
+
|
62
|
+
def encode(payload)
|
63
|
+
payload = JSON.generate(payload) unless payload.is_a?(String)
|
64
|
+
|
65
|
+
Base64.urlsafe_encode64(payload).tr('=', '')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/userlist/version.rb
CHANGED
data/userlist.gemspec
CHANGED
@@ -6,9 +6,9 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'userlist'
|
7
7
|
spec.version = Userlist::VERSION
|
8
8
|
spec.authors = ['Benedikt Deicke']
|
9
|
-
spec.email = ['benedikt@userlist.
|
9
|
+
spec.email = ['benedikt@userlist.com']
|
10
10
|
|
11
|
-
spec.summary = 'Ruby wrapper for the Userlist
|
11
|
+
spec.summary = 'Ruby wrapper for the Userlist API'
|
12
12
|
spec.homepage = 'http://github.com/userlistio/userlist-ruby'
|
13
13
|
spec.license = 'MIT'
|
14
14
|
|
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
|
-
spec.required_ruby_version = '>= 2.
|
22
|
+
spec.required_ruby_version = '>= 2.4'
|
23
23
|
|
24
|
-
spec.add_development_dependency 'bundler', '
|
25
|
-
spec.add_development_dependency '
|
24
|
+
spec.add_development_dependency 'bundler', '>= 1.15'
|
25
|
+
spec.add_development_dependency 'jwt', '~> 2.2'
|
26
|
+
spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
26
27
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
28
|
spec.add_development_dependency 'webmock', '~> 1.22'
|
28
29
|
end
|
metadata
CHANGED
@@ -1,43 +1,63 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: userlist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benedikt Deicke
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.15'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '12.3'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 12.3.3
|
34
51
|
type: :development
|
35
52
|
prerelease: false
|
36
53
|
version_requirements: !ruby/object:Gem::Requirement
|
37
54
|
requirements:
|
38
55
|
- - "~>"
|
39
56
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
57
|
+
version: '12.3'
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 12.3.3
|
41
61
|
- !ruby/object:Gem::Dependency
|
42
62
|
name: rspec
|
43
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,17 +86,17 @@ dependencies:
|
|
66
86
|
- - "~>"
|
67
87
|
- !ruby/object:Gem::Version
|
68
88
|
version: '1.22'
|
69
|
-
description:
|
89
|
+
description:
|
70
90
|
email:
|
71
|
-
- benedikt@userlist.
|
91
|
+
- benedikt@userlist.com
|
72
92
|
executables: []
|
73
93
|
extensions: []
|
74
94
|
extra_rdoc_files: []
|
75
95
|
files:
|
96
|
+
- ".github/workflows/test.yml"
|
76
97
|
- ".gitignore"
|
77
98
|
- ".rspec"
|
78
99
|
- ".rubocop.yml"
|
79
|
-
- ".travis.yml"
|
80
100
|
- CODE_OF_CONDUCT.md
|
81
101
|
- Gemfile
|
82
102
|
- Guardfile
|
@@ -90,18 +110,31 @@ files:
|
|
90
110
|
- lib/userlist/logging.rb
|
91
111
|
- lib/userlist/push.rb
|
92
112
|
- lib/userlist/push/client.rb
|
113
|
+
- lib/userlist/push/company.rb
|
114
|
+
- lib/userlist/push/event.rb
|
115
|
+
- lib/userlist/push/operations/create.rb
|
116
|
+
- lib/userlist/push/operations/delete.rb
|
117
|
+
- lib/userlist/push/relation.rb
|
118
|
+
- lib/userlist/push/relationship.rb
|
119
|
+
- lib/userlist/push/resource.rb
|
120
|
+
- lib/userlist/push/resource_collection.rb
|
121
|
+
- lib/userlist/push/serializer.rb
|
93
122
|
- lib/userlist/push/strategies.rb
|
94
123
|
- lib/userlist/push/strategies/direct.rb
|
95
124
|
- lib/userlist/push/strategies/null.rb
|
125
|
+
- lib/userlist/push/strategies/sidekiq.rb
|
126
|
+
- lib/userlist/push/strategies/sidekiq/worker.rb
|
96
127
|
- lib/userlist/push/strategies/threaded.rb
|
97
128
|
- lib/userlist/push/strategies/threaded/worker.rb
|
129
|
+
- lib/userlist/push/user.rb
|
130
|
+
- lib/userlist/token.rb
|
98
131
|
- lib/userlist/version.rb
|
99
132
|
- userlist.gemspec
|
100
133
|
homepage: http://github.com/userlistio/userlist-ruby
|
101
134
|
licenses:
|
102
135
|
- MIT
|
103
136
|
metadata: {}
|
104
|
-
post_install_message:
|
137
|
+
post_install_message:
|
105
138
|
rdoc_options: []
|
106
139
|
require_paths:
|
107
140
|
- lib
|
@@ -109,15 +142,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
142
|
requirements:
|
110
143
|
- - ">="
|
111
144
|
- !ruby/object:Gem::Version
|
112
|
-
version: '2.
|
145
|
+
version: '2.4'
|
113
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
147
|
requirements:
|
115
148
|
- - ">="
|
116
149
|
- !ruby/object:Gem::Version
|
117
150
|
version: '0'
|
118
151
|
requirements: []
|
119
|
-
rubygems_version: 3.
|
120
|
-
signing_key:
|
152
|
+
rubygems_version: 3.1.4
|
153
|
+
signing_key:
|
121
154
|
specification_version: 4
|
122
|
-
summary: Ruby wrapper for the Userlist
|
155
|
+
summary: Ruby wrapper for the Userlist API
|
123
156
|
test_files: []
|