togglehq 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|