togglehq 1.0.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +173 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/togglehq/config.rb +13 -0
- data/lib/togglehq/notify/notification.rb +75 -0
- data/lib/togglehq/notify/preferences.rb +26 -0
- data/lib/togglehq/notify/user_preferences.rb +70 -0
- data/lib/togglehq/notify.rb +3 -0
- data/lib/togglehq/request.rb +109 -0
- data/lib/togglehq/user.rb +52 -0
- data/lib/togglehq/version.rb +3 -0
- data/lib/togglehq.rb +41 -0
- data/togglehq.gemspec +33 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9e9a3e30065d07e0093a28ec7d427fc0f75f1c57
|
4
|
+
data.tar.gz: 721d571e9201b23658e35462ea70158ef6440cf3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4abb7be7cf8900c032abb5085c739fcddcbc3dba5017fafdc45483183d0b6ea5675427d475a894246e98c1704a3c09167843aa5beea37bcecb7cfce1b3110e87
|
7
|
+
data.tar.gz: 078c8177e6942d549eef97728f1b1b902c4ccdb561dcc9f381a09d8f662bc88fc9272f93c640eeee463aa27da0532780a9377097fb89ff0cc4781b621dacf895
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 ToggleHQ, LLC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# togglehq
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'togglehq'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install togglehq
|
18
|
+
|
19
|
+
## Configuration
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'togglehq'
|
23
|
+
|
24
|
+
Togglehq.configure do |config|
|
25
|
+
# These should be set to the "Master OAuth" client id and client secret
|
26
|
+
# for your app from the ToggleHQ dashboard
|
27
|
+
config.client_id = ENV['TOGGLEHQ_CLIENT_ID']
|
28
|
+
config.client_secret = ENV['TOGGLEHQ_CLIENT_SECRET']
|
29
|
+
|
30
|
+
# To log the HTTP requests/responses to and from the ToggleHQ API, set log_requests to true (defaults to false)
|
31
|
+
config.log_requests = true
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### Users
|
38
|
+
|
39
|
+
Create a user for your app
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
user = Togglehq::User.new(:identifier => "abcdef0123456789")
|
43
|
+
user.save
|
44
|
+
```
|
45
|
+
|
46
|
+
Find an existing user for your app
|
47
|
+
```ruby
|
48
|
+
user = Togglehq::User.find_by_identifier("abcdef0123456789")
|
49
|
+
```
|
50
|
+
|
51
|
+
If a user with the given identifier cannot be found, `nil` will be returned.
|
52
|
+
|
53
|
+
Alternatively, you can call `Togglehq::User.find_by_identifier!`, which will raise a RuntimeError if the given user cannot be found.
|
54
|
+
|
55
|
+
|
56
|
+
### ToggleHQ Notify Usage
|
57
|
+
|
58
|
+
|
59
|
+
#### Preferences
|
60
|
+
|
61
|
+
Get all preference categories and preferences for your app
|
62
|
+
```ruby
|
63
|
+
preferences = Togglehq::Notify::Preferences.all
|
64
|
+
```
|
65
|
+
|
66
|
+
A `Togglehq::Notify::Preferences` object has a `categories` attribute which contains an array of all preference categories:
|
67
|
+
```ruby
|
68
|
+
preferences.categories
|
69
|
+
=> [{"name"=>"Friends", "key"=>"friends", "preferences"=>[{"name"=>"Friend Request", "key"=>"friend_request", "default"=>true}]}]
|
70
|
+
```
|
71
|
+
|
72
|
+
Each preference category contains a name, a key, and an array of preferences, which also have a name, key, and default value.
|
73
|
+
|
74
|
+
|
75
|
+
#### User Preferences
|
76
|
+
|
77
|
+
`Togglehq::Notify::UserPreferences` enapsulates a specific user's notification preferences for your app.
|
78
|
+
Create one by passing a `Togglehq::User` object:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
user_preferences = Togglehq::Notify::UserPreferences.new(user)
|
82
|
+
```
|
83
|
+
|
84
|
+
Get the user's preferences by calling the `categories` method:
|
85
|
+
```ruby
|
86
|
+
user_preferences.categories
|
87
|
+
=> [{"name"=>"Friends", "key"=>"friends", "preferences"=>[{"name"=>"Friend Request", "key"=>"friend_request", "default"=>true, "enabled"=>true}]}]
|
88
|
+
```
|
89
|
+
|
90
|
+
Like `Togglehq::Notify::Preferences`, a `Togglehq::Notify::UserPreferences` object has a `categories` attribute which contains an array of all preference categories.
|
91
|
+
Each preference category contains a name, a key, and an array of preferences, which also have a name, key, and default value.
|
92
|
+
In addition, each user preference contains an enabled flag, indicating whether the user has enabled that particular preference or not.
|
93
|
+
|
94
|
+
Please note that a `Togglehq::Notify::UserPreferences` object's `categories` property is memoized when fetched from the ToggleHQ API. To reload
|
95
|
+
the preferences, call the `reload!` method on the `Togglehq::Notify::UserPreferences` object:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
user_preferences.reload!
|
99
|
+
```
|
100
|
+
|
101
|
+
Enable a preference for a user
|
102
|
+
```ruby
|
103
|
+
user_preferences.enable_preference!("category_key", "preference_key")
|
104
|
+
```
|
105
|
+
This will return true upon success, and raise a RuntimeError on failure.
|
106
|
+
|
107
|
+
Disable a preference for a user
|
108
|
+
```ruby
|
109
|
+
user_preferences.disable_preference!("category_key", "preference_key")
|
110
|
+
```
|
111
|
+
This will return true upon success, and raise a RuntimeError on failure.
|
112
|
+
|
113
|
+
#### Notifications
|
114
|
+
|
115
|
+
To send push notifications, first construct a `Togglehq::Notify::Notification` object specifying a preference category key, preference key, and message.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
notification = Togglehq::Notify::Notification.new(:category_key => "friends", :preference_key => "friend_request", :message => "You have a new friend request!")
|
119
|
+
```
|
120
|
+
To send this notification to a single user:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
user = Togglehq::User.find_by_identifier("abc123")
|
124
|
+
notification.send(user)
|
125
|
+
```
|
126
|
+
This will return true upon success, and raise a RuntimeError on failure.
|
127
|
+
|
128
|
+
To send this notification to a batch of users:
|
129
|
+
```ruby
|
130
|
+
user1 = Togglehq::User.new(:identifier => "abc123")
|
131
|
+
user2 = Togglehq::User.new(:identifier => "def456")
|
132
|
+
...
|
133
|
+
userN = Togglehq::User.new(:identifier => "xyz890")
|
134
|
+
|
135
|
+
notification.batch_send([user1, user2, ..., user2])
|
136
|
+
```
|
137
|
+
This will return true upon success, and raise a RuntimeError on failure.
|
138
|
+
|
139
|
+
To send this notification as a global message to all of the users in your app:
|
140
|
+
```ruby
|
141
|
+
notification.send_global
|
142
|
+
```
|
143
|
+
This will return true upon success, and raise a RuntimeError on failure.
|
144
|
+
|
145
|
+
|
146
|
+
## Gotchas
|
147
|
+
|
148
|
+
If you encounter SSL errors while using the togglehq-gem similar to the following:
|
149
|
+
|
150
|
+
```
|
151
|
+
Faraday::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
|
152
|
+
```
|
153
|
+
|
154
|
+
ToggleHQ's SSL certificate is issued by Comodo. Comodo recently added a new certificate root, which may not be in your Ruby/OpenSSL trusted root certificates file. To find the location of your root file:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
require 'openssl'
|
158
|
+
puts OpenSSL::X509::DEFAULT_CERT_FILE
|
159
|
+
```
|
160
|
+
|
161
|
+
This will output something like `/usr/local/etc/openssl/cert.pem`. Open this file, and add the "Comodo RSA Certification Authority (SHA-2)"" root cert PEM found [here](https://support.comodo.com/index.php?/Default/Knowledgebase/Article/View/969/108/root-comodo-rsa-certification-authority-sha-2) to this file.
|
162
|
+
|
163
|
+
For more gory details, [see this excellent blog post](http://mislav.net/2013/07/ruby-openssl/) and this [StackOverflow question](http://stackoverflow.com/questions/36966650/ruby-nethttp-responds-with-opensslsslsslerror-certificate-verify-failed).
|
164
|
+
|
165
|
+
|
166
|
+
## Contributing
|
167
|
+
|
168
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/togglehq/togglehq-gem.
|
169
|
+
|
170
|
+
|
171
|
+
## License
|
172
|
+
|
173
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "togglehq"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Togglehq
|
2
|
+
module Notify
|
3
|
+
class Notification
|
4
|
+
attr_accessor :category_key, :preference_key, :message
|
5
|
+
|
6
|
+
def initialize(params = {})
|
7
|
+
@category_key = params[:category_key]
|
8
|
+
@preference_key = params[:preference_key]
|
9
|
+
@message = params[:message]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sends this notification to the given user.
|
13
|
+
# @param user [Togglehq::Notify::User] the user to send the notification to
|
14
|
+
# @raise [RuntimeError] raised if an error occurs sending the notification
|
15
|
+
def send(user)
|
16
|
+
response = Togglehq::Request.new("/notifications",
|
17
|
+
{:notification => {:category => self.category_key,
|
18
|
+
:preference => self.preference_key,
|
19
|
+
:message => self.message,
|
20
|
+
:user => user.identifier}}).post!
|
21
|
+
if response.status == 403
|
22
|
+
raise "Access denied. You must use your Master OAuth client_id and client_secret to send push notifications."
|
23
|
+
elsif response.status == 404 || response.status == 422
|
24
|
+
json = JSON.parse(response.body)
|
25
|
+
raise json["message"]
|
26
|
+
elsif response.status == 200
|
27
|
+
return true
|
28
|
+
else
|
29
|
+
raise "Unexpected error sending notification"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Sends this notification to the given set of users. You may only send to up to 100 users at a time.
|
34
|
+
# @param users [array of Togglehq::Notify::User] the users to send the notification to
|
35
|
+
# @raise [RuntimeError] raised if an error occurs sending the notification
|
36
|
+
def batch_send(users)
|
37
|
+
response = Togglehq::Request.new("/notifications",
|
38
|
+
{:notification => {:category => self.category_key,
|
39
|
+
:preference => self.preference_key,
|
40
|
+
:message => self.message,
|
41
|
+
:users => users.map {|u| u.identifier}}}).post!
|
42
|
+
if response.status == 403
|
43
|
+
raise "Access denied. You must use your Master OAuth client_id and client_secret to send push notifications."
|
44
|
+
elsif response.status == 404 || response.status == 422
|
45
|
+
json = JSON.parse(response.body)
|
46
|
+
raise json["message"]
|
47
|
+
elsif response.status == 200
|
48
|
+
return true
|
49
|
+
else
|
50
|
+
raise "Unexpected error sending batch notification"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sends this notification as a global notification to all of this app's users.
|
55
|
+
# @raise [RuntimeError] raised if an error occurs sending the notification
|
56
|
+
def send_global
|
57
|
+
response = Togglehq::Request.new("/notifications",
|
58
|
+
{:notification => {:category => self.category_key,
|
59
|
+
:preference => self.preference_key,
|
60
|
+
:message => self.message,
|
61
|
+
:global => true}}).post!
|
62
|
+
if response.status == 403
|
63
|
+
raise "Access denied. You must use your Master OAuth client_id and client_secret to send push notifications."
|
64
|
+
elsif response.status == 404 || response.status == 422
|
65
|
+
json = JSON.parse(response.body)
|
66
|
+
raise json["message"]
|
67
|
+
elsif response.status == 200
|
68
|
+
return true
|
69
|
+
else
|
70
|
+
raise "Unexpected error sending global notification"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Togglehq
|
4
|
+
module Notify
|
5
|
+
class Preferences
|
6
|
+
attr_accessor :categories
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@categories = params[:categories]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets all available notification categories and their associated preferences for the current app
|
13
|
+
# @return an array of notification categories
|
14
|
+
def self.all
|
15
|
+
response = Togglehq::Request.new("/preferences").get!
|
16
|
+
if response.status == 200
|
17
|
+
json = JSON.parse(response.body)
|
18
|
+
preferences = Togglehq::Notify::Preferences.new(categories: json)
|
19
|
+
return preferences
|
20
|
+
else
|
21
|
+
raise "Unexpected error getting app preferences"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Togglehq
|
4
|
+
module Notify
|
5
|
+
class UserPreferences < SimpleDelegator
|
6
|
+
|
7
|
+
# Gets the current preferences for this user.
|
8
|
+
def categories
|
9
|
+
@categories ||= reload!
|
10
|
+
end
|
11
|
+
|
12
|
+
# Enables a preference for this user.
|
13
|
+
# @param category_key [String] the key of the preference category
|
14
|
+
# @param preference_key [String] the key of the preference within the category
|
15
|
+
# @raise [RuntimeError] raised if either the category or preference keys are invalid
|
16
|
+
def enable_preference!(category_key, preference_key)
|
17
|
+
response = Togglehq::Request.new("/preferences/enable",
|
18
|
+
{"user" => {"identifier" => self.identifier}, "category" => category_key, "preference" => preference_key}).patch!
|
19
|
+
if response.status == 200
|
20
|
+
if @categories
|
21
|
+
category = @categories.find {|g| g["key"] == category_key}
|
22
|
+
preference = category["preferences"].find {|s| s["key"] == preference_key} if category
|
23
|
+
preference["enabled"] = true if preference
|
24
|
+
end
|
25
|
+
return true
|
26
|
+
elsif response.status == 404
|
27
|
+
json = JSON.parse(response.body)
|
28
|
+
raise json["message"]
|
29
|
+
else
|
30
|
+
raise "unexpected error enabling preference"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Disables a preference for this user.
|
35
|
+
# @param cateogry_key [String] the key of the preference category
|
36
|
+
# @param preference_key [String] the key of the preference within the category
|
37
|
+
# @raise [RuntimeError] raised if either the category or preference keys are invalid
|
38
|
+
def disable_preference!(category_key, preference_key)
|
39
|
+
response = Togglehq::Request.new("/preferences/disable",
|
40
|
+
{"user" => {"identifier" => self.identifier}, "category" => category_key, "preference" => preference_key}).patch!
|
41
|
+
if response.status == 200
|
42
|
+
if @categories
|
43
|
+
category = @categories.find {|g| g["key"] == category_key}
|
44
|
+
preference = category["preferences"].find {|s| s["key"] == preference_key} if category
|
45
|
+
preference["enabled"] = false if preference
|
46
|
+
end
|
47
|
+
return true
|
48
|
+
elsif response.status == 404
|
49
|
+
json = JSON.parse(response.body)
|
50
|
+
raise json["message"]
|
51
|
+
else
|
52
|
+
raise "unexpected error disabling preference"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Reloads this UserPreferences from the ToggleHQ API
|
57
|
+
def reload!
|
58
|
+
response = Togglehq::Request.new("/preferences", {"user" => {"identifier" => self.identifier}}).get!
|
59
|
+
if response.status == 200
|
60
|
+
@categories = JSON.parse(response.body)
|
61
|
+
return @categories
|
62
|
+
elsif response.status == 404
|
63
|
+
raise "user not found"
|
64
|
+
else
|
65
|
+
raise "Unexpected error getting user preferences"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module Togglehq
|
6
|
+
class Request
|
7
|
+
|
8
|
+
V1 = "application/vnd.togglehq.com;version=1"
|
9
|
+
ACCESS_TOKEN_KEY = "togglehq-api-access-token"
|
10
|
+
|
11
|
+
attr_accessor :path, :params
|
12
|
+
attr_reader :headers
|
13
|
+
|
14
|
+
def initialize(path="", params={}, version=V1)
|
15
|
+
@path = path
|
16
|
+
@params = params
|
17
|
+
@headers = {
|
18
|
+
'Accept' => version,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def get!
|
23
|
+
request(:get, path, params)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post!
|
27
|
+
request(:post, path, params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def put!
|
31
|
+
request(:put, path, params)
|
32
|
+
end
|
33
|
+
|
34
|
+
def patch!
|
35
|
+
request(:patch, path, params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete!
|
39
|
+
request(:delete, path, params)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def request(method, path, params)
|
46
|
+
ensure_togglehq_api_access_token
|
47
|
+
conn = authenticated_togglehq_api_connection
|
48
|
+
response = conn.send(method) do |req|
|
49
|
+
req.url path
|
50
|
+
req.headers['Content-Type'] = 'application/json'
|
51
|
+
req.headers.merge!(headers)
|
52
|
+
req.body = params.to_json
|
53
|
+
end
|
54
|
+
response
|
55
|
+
end
|
56
|
+
|
57
|
+
def togglehq_api_connection
|
58
|
+
conn = Togglehq.connection
|
59
|
+
basic = Base64.strict_encode64("#{Togglehq.config.client_id}:#{Togglehq.config.client_secret}")
|
60
|
+
conn.headers.merge!({'Authorization' => "Basic #{basic}"})
|
61
|
+
conn
|
62
|
+
end
|
63
|
+
|
64
|
+
def authenticated_togglehq_api_connection
|
65
|
+
token = Togglehq.cache[ACCESS_TOKEN_KEY]
|
66
|
+
conn = Togglehq.connection
|
67
|
+
conn.headers.merge!({'Authorization' => "Bearer #{token["access_token"]}"})
|
68
|
+
conn
|
69
|
+
end
|
70
|
+
|
71
|
+
def ensure_togglehq_api_access_token
|
72
|
+
token = Togglehq.cache[ACCESS_TOKEN_KEY]
|
73
|
+
if !token.nil?
|
74
|
+
expires_at = Time.at(token["created_at"] + token["expires_in"])
|
75
|
+
if expires_at <= Time.now
|
76
|
+
get_new_access_token!
|
77
|
+
end
|
78
|
+
else
|
79
|
+
get_new_access_token!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_new_access_token!
|
84
|
+
response = togglehq_api_connection.post do |req|
|
85
|
+
req.url "/oauth/token"
|
86
|
+
req.headers['Content-Type'] = 'application/json'
|
87
|
+
req.body = {grant_type: "client_credentials", scope: "togglehq-lib"}.to_json
|
88
|
+
end
|
89
|
+
begin
|
90
|
+
response_document = JSON.parse(response.body)
|
91
|
+
if response_document.has_key?("error")
|
92
|
+
process_api_error(response_document)
|
93
|
+
else
|
94
|
+
Togglehq.cache[ACCESS_TOKEN_KEY] = response_document
|
95
|
+
end
|
96
|
+
rescue JSON::ParserError
|
97
|
+
raise "Fatal: unexpected response from ToggleHQ API: #{response.body}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def process_api_error(response_document)
|
102
|
+
if response_document["error"] == "invalid_client"
|
103
|
+
raise "Could not authenticate with ToggleHQ API: invalid client_id and/or client_secret."
|
104
|
+
else
|
105
|
+
raise "Unexpected error from ToggleHQ API: #{response_document["error_description"]}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Togglehq
|
2
|
+
class User
|
3
|
+
attr_accessor :identifier
|
4
|
+
|
5
|
+
def initialize(params = {})
|
6
|
+
@identifier = params[:identifier]
|
7
|
+
end
|
8
|
+
|
9
|
+
# Finds an app user by the given identifier. If no record is found, returns nil.
|
10
|
+
def self.find_by_identifier(identifier)
|
11
|
+
response = Togglehq::Request.new("/users/#{identifier}").get!
|
12
|
+
if response.status == 404
|
13
|
+
return nil
|
14
|
+
elsif response.status == 200
|
15
|
+
json = JSON.parse(response.body)
|
16
|
+
user = Togglehq::User.new(:identifier => identifier)
|
17
|
+
user.persisted!
|
18
|
+
return user
|
19
|
+
else
|
20
|
+
raise "Unexpected error finding user"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Like find_by_identifier, except that if no record is found, raises an RuntimeError.
|
25
|
+
def self.find_by_identifier!(identifier)
|
26
|
+
user = self.find_by_identifier(identifier)
|
27
|
+
raise "Could not find user with identifier #{identifier}" if user.nil?
|
28
|
+
return user
|
29
|
+
end
|
30
|
+
|
31
|
+
# Saves a new user
|
32
|
+
def save
|
33
|
+
response = Togglehq::Request.new("/users", {"user" => {"identifier" => self.identifier}}).post!
|
34
|
+
if response.status == 200
|
35
|
+
self.persisted!
|
36
|
+
json = JSON.parse(response.body)
|
37
|
+
if json.has_key?("message") && json["message"] == "user already exists"
|
38
|
+
# load this user's preferences
|
39
|
+
user = Togglehq::User.find_by_identifier(self.identifier)
|
40
|
+
end
|
41
|
+
return true
|
42
|
+
else
|
43
|
+
raise "unexpected error saving user"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @private
|
48
|
+
def persisted!
|
49
|
+
@persisted = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/togglehq.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'togglehq/version'
|
2
|
+
require 'togglehq/config'
|
3
|
+
require 'togglehq/request'
|
4
|
+
require 'togglehq/user'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
require 'togglehq/notify'
|
8
|
+
|
9
|
+
module Togglehq
|
10
|
+
class << self
|
11
|
+
attr_writer :config, :cache
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.config
|
15
|
+
@config ||= Config.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.cache
|
19
|
+
@cache ||= Hash.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reset
|
23
|
+
@config = Config.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.logger
|
27
|
+
@logger ||= ::Logger.new(STDOUT)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configure
|
31
|
+
yield config
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.connection
|
35
|
+
conn = Faraday.new(:url => config.uri) do |faraday|
|
36
|
+
faraday.adapter :net_http_persistent
|
37
|
+
faraday.response :logger, self.logger, bodies: true if config.log_requests
|
38
|
+
end
|
39
|
+
conn
|
40
|
+
end
|
41
|
+
end
|
data/togglehq.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'togglehq/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "togglehq"
|
8
|
+
spec.version = Togglehq::VERSION
|
9
|
+
spec.authors = ["Toggle"]
|
10
|
+
spec.email = ["support@togglehq.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Ruby gem wrapper for the ToggleHQ API}
|
13
|
+
spec.description = %q{Ruby gem wrapper for the ToggleHQ API}
|
14
|
+
spec.homepage = "https://github.com/togglehq/togglehq-gem"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
|
26
|
+
spec.add_development_dependency "vcr"
|
27
|
+
spec.add_development_dependency "webmock"
|
28
|
+
spec.add_development_dependency "simplecov"
|
29
|
+
|
30
|
+
spec.add_dependency "faraday"
|
31
|
+
spec.add_dependency "net-http-persistent"
|
32
|
+
spec.add_dependency "json"
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: togglehq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Toggle
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: vcr
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faraday
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: net-http-persistent
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: json
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Ruby gem wrapper for the ToggleHQ API
|
140
|
+
email:
|
141
|
+
- support@togglehq.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
148
|
+
- ".travis.yml"
|
149
|
+
- Gemfile
|
150
|
+
- LICENSE.txt
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- bin/console
|
154
|
+
- bin/setup
|
155
|
+
- lib/togglehq.rb
|
156
|
+
- lib/togglehq/config.rb
|
157
|
+
- lib/togglehq/notify.rb
|
158
|
+
- lib/togglehq/notify/notification.rb
|
159
|
+
- lib/togglehq/notify/preferences.rb
|
160
|
+
- lib/togglehq/notify/user_preferences.rb
|
161
|
+
- lib/togglehq/request.rb
|
162
|
+
- lib/togglehq/user.rb
|
163
|
+
- lib/togglehq/version.rb
|
164
|
+
- togglehq.gemspec
|
165
|
+
homepage: https://github.com/togglehq/togglehq-gem
|
166
|
+
licenses:
|
167
|
+
- MIT
|
168
|
+
metadata: {}
|
169
|
+
post_install_message:
|
170
|
+
rdoc_options: []
|
171
|
+
require_paths:
|
172
|
+
- lib
|
173
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
requirements: []
|
184
|
+
rubyforge_project:
|
185
|
+
rubygems_version: 2.4.6
|
186
|
+
signing_key:
|
187
|
+
specification_version: 4
|
188
|
+
summary: Ruby gem wrapper for the ToggleHQ API
|
189
|
+
test_files: []
|