fitbit-omni-api 0.0.1
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/LICENSE.md +20 -0
- data/README.md +93 -0
- data/Rakefile +2 -0
- data/lib/api/fitbit_api.rb +767 -0
- data/lib/fitbit-omni-api.rb +3 -0
- data/lib/fitbit-omni-api/version.rb +7 -0
- data/lib/omniauth/strategies/fitbit.rb +49 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3bb58a076555dbaeef38610a7e7cc2035542d1f5
|
4
|
+
data.tar.gz: 1295e14ef5ce64bb429779109eac458c318f524d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0dbc41a2b02902432761fd992bda76de1cb5885cdf4d231bb851c235ee57d7be5a12ad21c4c33504fc79c7ba390f8ff8808643499b523549988550d945b07127
|
7
|
+
data.tar.gz: 8fc3c5c81be51e371f440f75c3fd033412c9dcf2dce1da073704123313c75946d804bbde0fe2df524061c01fe7b83029db331782a819b2079479355b2c8bec6a
|
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 TK Gospodinov, (c) Scott McGrath
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Fitbit OmniAuth Strategy
|
2
|
+
|
3
|
+
This gem is an OmniAuth 1.0+ Strategy for the [Fitbit API](https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API).
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
Add the strategy to your `Gemfile`:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'fitbit-omni-api'
|
11
|
+
```
|
12
|
+
|
13
|
+
Then integrate the strategy into your middleware:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
use OmniAuth::Builder do
|
17
|
+
provider :fitbit, 'consumer_key', 'consumer_secret'
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
In Rails, create a new file under config/initializers called omniauth.rb to plug the strategy into your middleware stack.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
25
|
+
provider :fitbit, 'consumer_key', 'consumer_secret'
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
To register your application with Fitbit and obtain a consumer key and secret, go to the [Fitbit application registration](https://dev.fitbit.com/apps/new).
|
30
|
+
|
31
|
+
For additional information about OmniAuth, visit [OmniAuth wiki](https://github.com/intridea/omniauth/wiki).
|
32
|
+
|
33
|
+
For a short tutorial on how to use OmniAuth in your Rails application, visit [this tutsplus.com tutorial](http://net.tutsplus.com/tutorials/ruby/how-to-use-omniauth-to-authenticate-your-users/).
|
34
|
+
|
35
|
+
## Accessing the Fitbit API
|
36
|
+
|
37
|
+
An API call can be instantiated with `Fitbit::Api.new({}).api_call()`
|
38
|
+
Each call requires:
|
39
|
+
* Fitbit consumer_key and consumer_secret
|
40
|
+
* A params Hash containing the Fitbit API method, plus all required parameters
|
41
|
+
* Optionally, for authenticated API calls, your user's Fitbit auth token and auth secret
|
42
|
+
|
43
|
+
An example of an authenticated API call:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
Fitbit::Api.new({}).api_call(
|
47
|
+
'consumer_key',
|
48
|
+
'consumer_secret',
|
49
|
+
params,
|
50
|
+
'auth_token',
|
51
|
+
'auth_secret'
|
52
|
+
)
|
53
|
+
```
|
54
|
+
|
55
|
+
OmniAuth Fitbit supports the Fitbit Resource Access API and the Fitbit Subscriptions API.
|
56
|
+
|
57
|
+
To access the Resource Access API, consult the API docs and provide the required parameters. For example,
|
58
|
+
the API-Search-Foods method requires 'api-version', 'query' and 'response-format'. There's also an optional
|
59
|
+
Request Header parameter, 'Accept-Locale'. A call to API-Search-Foods might look like this:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
def fitbit_foods_search
|
63
|
+
params = {
|
64
|
+
'api-method' => 'api-search-foods',
|
65
|
+
'query' => 'buffalo chicken',
|
66
|
+
'response-format' => 'json',
|
67
|
+
'Accept-Locale' => 'en_US',
|
68
|
+
}
|
69
|
+
request = Fitbit::Api.new({}).api_call(
|
70
|
+
'consumer_key',
|
71
|
+
'consumer_secret',
|
72
|
+
params,
|
73
|
+
'auth_token',
|
74
|
+
'auth_secret'
|
75
|
+
)
|
76
|
+
@response = request.body
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
A few notes: 'api-version' defaults to '1' and can be omitted from Fitbit-Omni-Api calls.
|
81
|
+
If you omit the 'response-format', the response will be in the default xml format.
|
82
|
+
Some authenticated API methods can be accessed without auth tokens, if you supply a user's
|
83
|
+
user-id (see the API docs for details).
|
84
|
+
|
85
|
+
To access the Subscription API, two new api methods were created just for this gem:
|
86
|
+
API-Create-Subscription and API-Delete-Subscription. These api methods only exist in this gem,
|
87
|
+
not the Fitbit API. If you consult the Subscription API docs for adding and deleting subscriptions,
|
88
|
+
and supply the required parameters, these two api methods work just as described for the
|
89
|
+
Resource Access API. NOTE: To subscribe to ALL of a user's changes, make 'collection-path' = 'all'.
|
90
|
+
|
91
|
+
## Copyright
|
92
|
+
|
93
|
+
Copyright (c) 2012 TK Gospodinov, (c) Scott McGrath 2013. See [LICENSE](https://github.com/tkgospodinov/omniauth-fitbit/blob/master/LICENSE.md) for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,767 @@
|
|
1
|
+
module Fitbit
|
2
|
+
class Api < OmniAuth::Strategies::Fitbit
|
3
|
+
|
4
|
+
def api_call consumer_key, consumer_secret, params, auth_token="", auth_secret=""
|
5
|
+
api_params = get_lowercase_api_method(params)
|
6
|
+
api_method = api_params['api-method']
|
7
|
+
fitbit = @@fitbit_methods[api_method]
|
8
|
+
api_error = get_api_errors(api_params.keys, fitbit, auth_token, auth_secret)
|
9
|
+
raise "#{api_method} " + api_error if api_error
|
10
|
+
access_token = build_request(consumer_key, consumer_secret, auth_token, auth_secret)
|
11
|
+
send_api_request(api_params, fitbit, access_token)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_fitbit_methods
|
15
|
+
@@fitbit_methods
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def get_lowercase_api_method params
|
21
|
+
params['api-method'] ||= nil
|
22
|
+
params['api-method'].downcase!
|
23
|
+
params
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_api_errors params_keys, fitbit, auth_token="", auth_secret=""
|
27
|
+
if fitbit
|
28
|
+
no_auth_tokens = true if (auth_token == "" or auth_secret == "")
|
29
|
+
get_error_message(params_keys, fitbit, no_auth_tokens)
|
30
|
+
else
|
31
|
+
"is not a valid Fitbit API method."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_error_message params_keys, fitbit, no_auth_tokens
|
36
|
+
if missing_url_parameters? fitbit['url_parameters'], params_keys
|
37
|
+
url_parameters_error(fitbit['url_parameters'], params_keys)
|
38
|
+
elsif fitbit['post_parameters'] and missing_post_parameters? fitbit['post_parameters'], params_keys
|
39
|
+
post_parameters_error(fitbit['post_parameters'], params_keys)
|
40
|
+
elsif fitbit['auth_required'] and no_auth_tokens
|
41
|
+
auth_error(fitbit['auth_required'], params_keys.include?('user-id'))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def missing_url_parameters? required, supplied
|
46
|
+
url_parameters = get_url_parameters(required, supplied)
|
47
|
+
required and supplied & url_parameters != url_parameters
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_url_parameters required, supplied
|
51
|
+
if required.is_a? Hash
|
52
|
+
get_dynamic_url_parameters(required, supplied)
|
53
|
+
else
|
54
|
+
required
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_dynamic_url_parameters required, supplied
|
59
|
+
required.keys.each do |x|
|
60
|
+
return required[x] if supplied.include? x
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def missing_post_parameters? required, supplied
|
65
|
+
error = nil
|
66
|
+
required.each do |k,v|
|
67
|
+
supplied_required = required[k] & supplied if k != 'required_if'
|
68
|
+
case k
|
69
|
+
when 'required'
|
70
|
+
error = k if supplied_required != required[k]
|
71
|
+
when 'exclusive'
|
72
|
+
error = k + '_too_few' if supplied_required.length < 1
|
73
|
+
error = k + '_too_many' if supplied_required.length > 1
|
74
|
+
when 'one_required'
|
75
|
+
error = k if supplied_required.length < 1
|
76
|
+
when 'required_if'
|
77
|
+
required[k].each do |key,val|
|
78
|
+
error = k if supplied.include? key and !supplied.include? val
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
error
|
83
|
+
end
|
84
|
+
|
85
|
+
def url_parameters_error required, supplied
|
86
|
+
if required.is_a? Hash
|
87
|
+
get_dynamic_url_error(required, supplied)
|
88
|
+
else
|
89
|
+
"requires #{required}. You're missing #{required-supplied}."
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_dynamic_url_error required, supplied
|
94
|
+
error = "requires 1 of #{required.length} options: "
|
95
|
+
required.keys.each_with_index do |x,i|
|
96
|
+
error << "(#{i+1}) #{required[x]} "
|
97
|
+
end
|
98
|
+
error
|
99
|
+
end
|
100
|
+
|
101
|
+
def post_parameters_error required, supplied
|
102
|
+
error_type = missing_post_parameters? required, supplied
|
103
|
+
e = 'exclusive' if error_type == 'exclusive_too_few' or error_type == 'exclusive_too_many'
|
104
|
+
e ||= error_type
|
105
|
+
|
106
|
+
case error_type
|
107
|
+
when 'required'
|
108
|
+
"requires POST parameters #{required[e]}. You're missing #{required[e]-supplied}."
|
109
|
+
when 'exclusive_too_few'
|
110
|
+
"requires one of these POST parameters: #{required[e]}."
|
111
|
+
when 'exclusive_too_many'
|
112
|
+
supplied_required = required[e] & supplied
|
113
|
+
supplied_required_string = supplied_required.join(' AND ')
|
114
|
+
"allows only one of these POST parameters #{required[e]}. You used #{supplied_required_string}."
|
115
|
+
when 'one_required'
|
116
|
+
"requires at least one of the following POST parameters: #{required[e]}."
|
117
|
+
when 'required_if'
|
118
|
+
required[e].each do |k,v|
|
119
|
+
if supplied.include? k and !supplied.include? v
|
120
|
+
return "requires POST parameter #{v} when you use POST parameter #{k}."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def auth_error auth_required, auth_supplied
|
127
|
+
if auth_required == 'user-id' and !auth_supplied
|
128
|
+
"requires user auth_token and auth_secret, unless you include [\"user-id\"]."
|
129
|
+
elsif auth_required != 'user-id'
|
130
|
+
"requires user auth_token and auth_secret."
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_request consumer_key, consumer_secret, auth_token, auth_secret
|
135
|
+
fitbit = Fitbit::Api.new :fitbit, consumer_key, consumer_secret
|
136
|
+
OAuth::AccessToken.new fitbit.consumer, auth_token, auth_secret
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_api_request params, fitbit, access_token
|
140
|
+
http_method = fitbit['http_method']
|
141
|
+
request_url = build_url(params, fitbit, http_method)
|
142
|
+
request_headers = get_request_headers(params, fitbit) if fitbit['request_headers']
|
143
|
+
|
144
|
+
if http_method == 'get' or http_method == 'delete'
|
145
|
+
access_token.request( http_method, "http://api.fitbit.com#{request_url}", request_headers )
|
146
|
+
else
|
147
|
+
access_token.request( http_method, "http://api.fitbit.com#{request_url}", "", request_headers )
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def build_url params, fitbit, http_method
|
152
|
+
api_version = @@api_version
|
153
|
+
api_url_resources = get_url_resources(params, fitbit)
|
154
|
+
api_format = get_response_format(params['response-format'])
|
155
|
+
api_post_parameters = get_post_parameters(params, fitbit) if http_method == 'post'
|
156
|
+
api_query = uri_encode_query(params['query'])
|
157
|
+
|
158
|
+
"/#{api_version}/#{api_url_resources}.#{api_format}#{api_query}#{api_post_parameters}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def get_post_parameters params, fitbit
|
162
|
+
return nil if is_subscription? params['api-method']
|
163
|
+
not_post_parameters = ['request_headers', 'url_parameters']
|
164
|
+
ignore = ['api-method', 'response-format']
|
165
|
+
not_post_parameters.each do |x|
|
166
|
+
fitbit[x].each { |y| ignore.push(y) } if fitbit[x]
|
167
|
+
end
|
168
|
+
post_parameters = params.select { |k,v| !ignore.include? k }
|
169
|
+
|
170
|
+
"?" + OAuth::Helper.normalize(post_parameters)
|
171
|
+
end
|
172
|
+
|
173
|
+
def get_request_headers params, fitbit
|
174
|
+
request_headers = fitbit['request_headers']
|
175
|
+
params.select { |k,v| request_headers.include? k }
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_url_resources params, fitbit
|
179
|
+
params_keys = params.keys
|
180
|
+
api_ids = get_url_parameters(fitbit['url_parameters'], params_keys)
|
181
|
+
api_resources = get_url_parameters(fitbit['resources'], params_keys)
|
182
|
+
dynamic_url = add_ids(params, api_ids, api_resources, fitbit['auth_required']) if api_ids or params['user-id']
|
183
|
+
dynamic_url ||= api_resources
|
184
|
+
dynamic_url.join("/")
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_ids params, api_ids, api_resources, auth_required
|
188
|
+
api_resources_copy = api_resources.dup
|
189
|
+
api_resources_copy.each_with_index do |x, i|
|
190
|
+
id = x.delete "<>"
|
191
|
+
|
192
|
+
if x == '-' and auth_required == 'user-id' and params['user-id']
|
193
|
+
api_resources_copy[i] = params['user-id']
|
194
|
+
elsif id == 'collection-path' and params[id] == 'all'
|
195
|
+
api_resources_copy.delete(x)
|
196
|
+
elsif id == 'subscription-id' and params['collection-path'] != 'all'
|
197
|
+
api_resources_copy[i] = params[id] + "-" + params['collection-path']
|
198
|
+
api_resources_copy.delete('<collection-path>')
|
199
|
+
elsif api_ids and api_ids.include? id and !api_ids.include? x
|
200
|
+
api_resources_copy[i] = params[id]
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def is_subscription? api_method
|
206
|
+
api_method == 'api-create-subscription' or api_method == 'api-delete-subscription'
|
207
|
+
end
|
208
|
+
|
209
|
+
def get_response_format api_format
|
210
|
+
api_format ? api_format.downcase : 'xml'
|
211
|
+
end
|
212
|
+
|
213
|
+
def uri_encode_query query
|
214
|
+
query ? "?" + OAuth::Helper.normalize({ 'query' => query }) : ""
|
215
|
+
end
|
216
|
+
|
217
|
+
@@api_version = 1
|
218
|
+
|
219
|
+
@@fitbit_methods = {
|
220
|
+
'api-accept-invite' => {
|
221
|
+
'auth_required' => true,
|
222
|
+
'http_method' => 'post',
|
223
|
+
'post_parameters' => {
|
224
|
+
'required' => ['accept'],
|
225
|
+
},
|
226
|
+
'url_parameters' => ['from-user-id'],
|
227
|
+
'resources' => ['user', '-', 'friends', 'invitations', '<from-user-id>'],
|
228
|
+
},
|
229
|
+
'api-add-favorite-activity' => {
|
230
|
+
'auth_required' => true,
|
231
|
+
'http_method' => 'post',
|
232
|
+
'url_parameters' => ['activity-id'],
|
233
|
+
'resources' => ['user', '-', 'activities', 'favorite', '<activity-id>'],
|
234
|
+
},
|
235
|
+
'api-add-favorite-food' => {
|
236
|
+
'auth_required' => true,
|
237
|
+
'http_method' => 'post',
|
238
|
+
'url_parameters' => ['food-id'],
|
239
|
+
'resources' => ['user', '-', 'foods', 'log', 'favorite', '<food-id>'],
|
240
|
+
},
|
241
|
+
'api-browse-activities' => {
|
242
|
+
'auth_required' => false,
|
243
|
+
'http_method' => 'get',
|
244
|
+
'request_headers' => ['Accept-Locale'],
|
245
|
+
'resources' => ['activities'],
|
246
|
+
},
|
247
|
+
'api-config-friends-leaderboard' => {
|
248
|
+
'auth_required' => true,
|
249
|
+
'http_method' => 'post',
|
250
|
+
'post_parameters' => {
|
251
|
+
'required' => ['hideMeFromLeaderboard'],
|
252
|
+
},
|
253
|
+
'request_headers' => ['Accept-Language'],
|
254
|
+
'resources' => ['user', '-', 'friends', 'leaderboard'],
|
255
|
+
},
|
256
|
+
'api-create-food' => {
|
257
|
+
'auth_required' => true,
|
258
|
+
'http_method' => 'post',
|
259
|
+
'post_parameters' => {
|
260
|
+
'required' => ['name', 'defaultFoodMeasurementUnitId', 'defaultServingSize', 'calories'],
|
261
|
+
},
|
262
|
+
'request_headers' => ['Accept-Locale'],
|
263
|
+
'resources' => ['foods'],
|
264
|
+
},
|
265
|
+
'api-create-invite' => {
|
266
|
+
'auth_required' => true,
|
267
|
+
'http_method' => 'post',
|
268
|
+
'post_parameters' => {
|
269
|
+
'exlusive' => ['invitedUserEmail', 'invitedUserId'],
|
270
|
+
},
|
271
|
+
'resources' => ['user', '-', 'friends', 'invitations'],
|
272
|
+
},
|
273
|
+
'api-create-subscription' => {
|
274
|
+
'auth_required' => true,
|
275
|
+
'http_method' => 'post',
|
276
|
+
'url_parameters' => ['collection-path', 'subscription-id'],
|
277
|
+
'request_headers' => ['X-Fitbit-Subscriber-Id'],
|
278
|
+
'resources' => ['user', '-', '<collection-path>', 'apiSubscriptions', '<subscription-id>', '<collection-path>']
|
279
|
+
},
|
280
|
+
'api-delete-activity-log' => {
|
281
|
+
'auth_required' => true,
|
282
|
+
'http_method' => 'delete',
|
283
|
+
'url_parameters' => ['activity-log-id'],
|
284
|
+
'resources' => ['user', '-', 'activities', '<activity-log-id>'],
|
285
|
+
},
|
286
|
+
'api-delete-blood-pressure-log' => {
|
287
|
+
'auth_required' => true,
|
288
|
+
'http_method' => 'delete',
|
289
|
+
'url_parameters' => ['bp-log-id'],
|
290
|
+
'resources' => ['user', '-', 'bp', '<bp-log-id>'],
|
291
|
+
},
|
292
|
+
'api-delete-body-fat-log' => {
|
293
|
+
'auth_required' => true,
|
294
|
+
'http_method' => 'delete',
|
295
|
+
'url_parameters' => ['body-fat-log-id'],
|
296
|
+
'resources' => ['user', '-', 'body', 'log', 'fat', '<body-fat-log-id>'],
|
297
|
+
},
|
298
|
+
'api-delete-body-weight-log' => {
|
299
|
+
'auth_required' => true,
|
300
|
+
'http_method' => 'delete',
|
301
|
+
'url_parameters' => ['body-weight-log-id'],
|
302
|
+
'resources' => ['user', '-', 'body', 'log', 'weight', '<body-weight-log-id>'],
|
303
|
+
},
|
304
|
+
'api-delete-favorite-activity' => {
|
305
|
+
'auth_required' => true,
|
306
|
+
'http_method' => 'delete',
|
307
|
+
'url_parameters' => ['activity-id'],
|
308
|
+
'resources' => ['user', '-', 'activities', 'favorite', '<activity-id>'],
|
309
|
+
},
|
310
|
+
'api-delete-favorite-food' => {
|
311
|
+
'auth_required' => true,
|
312
|
+
'http_method' => 'delete',
|
313
|
+
'url_parameters' => ['food-id'],
|
314
|
+
'resources' => ['user', '-', 'foods', 'log', 'favorite', '<food-id>'],
|
315
|
+
},
|
316
|
+
'api-delete-food-log' => {
|
317
|
+
'auth_required' => true,
|
318
|
+
'http_method' => 'delete',
|
319
|
+
'url_parameters' => ['food-log-id'],
|
320
|
+
'resources' => ['user', '-', 'foods', 'log', '<food-log-id>'],
|
321
|
+
},
|
322
|
+
'api-delete-heart-rate-log' => {
|
323
|
+
'auth_required' => true,
|
324
|
+
'http_method' => 'delete',
|
325
|
+
'url_parameters' => ['heart-log-id'],
|
326
|
+
'resources' => ['user', '-', 'heart', '<heart-log-id>'],
|
327
|
+
},
|
328
|
+
'api-delete-sleep-log' => {
|
329
|
+
'auth_required' => true,
|
330
|
+
'http_method' => 'delete',
|
331
|
+
'url_parameters' => ['sleep-log-id'],
|
332
|
+
'resources' => ['user', '-', 'sleep', '<sleep-log-id>'],
|
333
|
+
},
|
334
|
+
'api-delete-subscription' => {
|
335
|
+
'auth_required' => 'user-id',
|
336
|
+
'http_method' => 'delete',
|
337
|
+
'url_parameters' => ['collection-path', 'subscription-id'],
|
338
|
+
'resources' => ['user', '-', '<collection-path>', 'apiSubscriptions', '<subscription-id>', '<collection-path>']
|
339
|
+
},
|
340
|
+
'api-delete-water-log' => {
|
341
|
+
'auth_required' => true,
|
342
|
+
'http_method' => 'delete',
|
343
|
+
'url_parameters' => ['water-log-id'],
|
344
|
+
'resources' => ['user', '-', 'foods', 'log', 'water', '<water-log-id>'],
|
345
|
+
},
|
346
|
+
'api-devices-add-alarm' => {
|
347
|
+
'auth_required' => true,
|
348
|
+
'http_method' => 'post',
|
349
|
+
'post_parameters' => {
|
350
|
+
'required' => ['time', 'enabled', 'recurring', 'weekDays'],
|
351
|
+
},
|
352
|
+
'request_headers' => ['Accept-Language'],
|
353
|
+
'url_parameters' => ['device-id'],
|
354
|
+
'resources' => ['user', '-', 'devices', 'tracker', '<device-id>', 'alarms'],
|
355
|
+
},
|
356
|
+
'api-devices-delete-alarm' => {
|
357
|
+
'auth_required' => true,
|
358
|
+
'http_method' => 'delete',
|
359
|
+
'url_parameters' => ['device-id', 'alarm-id'],
|
360
|
+
'resources' => ['user', '-', 'devices', 'tracker', '<device-id>', 'alarms', '<alarm-id>'],
|
361
|
+
},
|
362
|
+
'api-devices-get-alarms' => {
|
363
|
+
'auth_required' => true,
|
364
|
+
'http_method' => 'get',
|
365
|
+
'url_parameters' => ['device-id'],
|
366
|
+
'resources' => ['user', '-', 'devices', 'tracker', '<device-id>', 'alarms'],
|
367
|
+
},
|
368
|
+
'api-devices-update-alarm' => {
|
369
|
+
'auth_required' => true,
|
370
|
+
'http_method' => 'post',
|
371
|
+
'post_parameters' => {
|
372
|
+
'required' => ['time', 'enabled', 'recurring', 'weekDays', 'snoozeLength', 'snoozeCount'],
|
373
|
+
},
|
374
|
+
'request_headers' => ['Accept-Language'],
|
375
|
+
'url_parameters' => ['device-id', 'alarm-id'],
|
376
|
+
'resources' => ['user', '-', 'devices', 'tracker', '<device-id>', 'alarms', '<alarm-id>'],
|
377
|
+
},
|
378
|
+
'api-get-activities' => {
|
379
|
+
'auth_required' => 'user-id',
|
380
|
+
'http_method' => 'get',
|
381
|
+
'request_headers' => ['Accept-Locale', 'Accept-Language'],
|
382
|
+
'url_parameters' => ['date'],
|
383
|
+
'resources' => ['user', '-', 'activities', 'date', '<date>'],
|
384
|
+
},
|
385
|
+
'api-get-activity' => {
|
386
|
+
'auth_required' => false,
|
387
|
+
'http_method' => 'get',
|
388
|
+
'request_headers' => ['Accept-Locale'],
|
389
|
+
'url_parameters' => ['activity-id'],
|
390
|
+
'resources' => ['activities', '<activity-id>'],
|
391
|
+
},
|
392
|
+
'api-get-activity-daily-goals' => {
|
393
|
+
'auth_required' => true,
|
394
|
+
'http_method' => 'get',
|
395
|
+
'request_headers' => ['Accept-Language'],
|
396
|
+
'resources' => ['user', '-', 'activities', 'goals', 'daily'],
|
397
|
+
},
|
398
|
+
'api-get-activity-stats' => {
|
399
|
+
'auth_required' => 'user-id',
|
400
|
+
'http_method' => 'get',
|
401
|
+
'request_headers' => ['Accept-Language'],
|
402
|
+
'resources' => ['user', '-', 'activities'],
|
403
|
+
},
|
404
|
+
'api-get-activity-weekly-goals' => {
|
405
|
+
'auth_required' => true,
|
406
|
+
'http_method' => 'get',
|
407
|
+
'request_headers' => ['Accept-Language'],
|
408
|
+
'resources' => ['user', '-', 'activities', 'goals', 'weekly'],
|
409
|
+
},
|
410
|
+
'api-get-badges' => {
|
411
|
+
'auth_required' => 'user-id',
|
412
|
+
'http_method' => 'get',
|
413
|
+
'request_headers' => ['Accept-Locale'],
|
414
|
+
'resources' => ['user', '-', 'badges'],
|
415
|
+
},
|
416
|
+
'api-get-blood-pressure' => {
|
417
|
+
'auth_required' => true,
|
418
|
+
'http_method' => 'get',
|
419
|
+
'url_parameters' => ['date'],
|
420
|
+
'resources' => ['user', '-', 'bp', 'date', '<date>'],
|
421
|
+
},
|
422
|
+
'api-get-body-fat' => {
|
423
|
+
'auth_required' => true,
|
424
|
+
'http_method' => 'get',
|
425
|
+
'url_parameters' => {
|
426
|
+
'date' => ['date'],
|
427
|
+
'end-date' => ['base-date', 'end-date'],
|
428
|
+
'period' => ['base-date', 'period'],
|
429
|
+
},
|
430
|
+
'request_headers' => ['Accept-Language'],
|
431
|
+
'resources' => {
|
432
|
+
'date' => ['user', '-', 'body', 'log', 'fat', 'date', '<date>'],
|
433
|
+
'end-date' => ['user', '-', 'body', 'log', 'fat', 'date', '<base-date>', '<end-date>'],
|
434
|
+
'period' => ['user', '-', 'body', 'log', 'fat', 'date', '<base-date>', '<period>'],
|
435
|
+
}
|
436
|
+
},
|
437
|
+
'api-get-body-fat-goal' => {
|
438
|
+
'auth_required' => true,
|
439
|
+
'http_method' => 'get',
|
440
|
+
'resources' => ['user', '-', 'body', 'log', 'fat', 'goal'],
|
441
|
+
},
|
442
|
+
'api-get-body-measurements' => {
|
443
|
+
'auth_required' => 'user-id',
|
444
|
+
'http_method' => 'get',
|
445
|
+
'request_headers' => ['Accept-Language'],
|
446
|
+
'url_parameters' => ['date'],
|
447
|
+
'resources' => ['user', '-', 'body', 'date', '<date>'],
|
448
|
+
},
|
449
|
+
'api-get-body-weight' => {
|
450
|
+
'auth_required' => true,
|
451
|
+
'http_method' => 'get',
|
452
|
+
'request_headers' => ['Accept-Language'],
|
453
|
+
'url_parameters' => {
|
454
|
+
'date' => ['date'],
|
455
|
+
'end-date' => ['base-date', 'end-date'],
|
456
|
+
'period' => ['base-date', 'period'],
|
457
|
+
},
|
458
|
+
'resources' => {
|
459
|
+
'date' => ['user', '-', 'body', 'log', 'weight', 'date', '<date>'],
|
460
|
+
'end-date' => ['user', '-', 'body', 'log', 'weight', 'date', '<base-date>', '<end-date>'],
|
461
|
+
'period' => ['user', '-', 'body', 'log', 'weight', 'date', '<base-date>', '<period>'],
|
462
|
+
}
|
463
|
+
},
|
464
|
+
'api-get-body-weight-goal' => {
|
465
|
+
'auth_required' => true,
|
466
|
+
'http_method' => 'get',
|
467
|
+
'request_headers' => ['Accept-Language'],
|
468
|
+
'resources' => ['user', '-', 'body', 'log', 'weight', 'goal'],
|
469
|
+
},
|
470
|
+
'api-get-device' => {
|
471
|
+
'auth_required' => 'user-id',
|
472
|
+
'http_method' => 'get',
|
473
|
+
'url_parameters' => ['device-id'],
|
474
|
+
'resources' => ['user', '-', 'devices', '<device-id>'],
|
475
|
+
},
|
476
|
+
'api-get-devices' => {
|
477
|
+
'auth_required' => true,
|
478
|
+
'http_method' => 'get',
|
479
|
+
'resources' => ['user', '-', 'devices'],
|
480
|
+
},
|
481
|
+
'api-get-favorite-activities' => {
|
482
|
+
'auth_required' => 'user-id',
|
483
|
+
'http_method' => 'get',
|
484
|
+
'request_headers' => ['Accept-Locale'],
|
485
|
+
'resources' => ['user', '-', 'activities', 'favorite'],
|
486
|
+
},
|
487
|
+
'api-get-favorite-foods' => {
|
488
|
+
'auth_required' => true,
|
489
|
+
'http_method' => 'get',
|
490
|
+
'resources' => ['user', '-', 'foods', 'log', 'favorite'],
|
491
|
+
},
|
492
|
+
'api-get-food' => {
|
493
|
+
'auth_required' => false,
|
494
|
+
'http_method' => 'get',
|
495
|
+
'request_headers' => ['Accept-Locale'],
|
496
|
+
'url_parameters' => ['food-id'],
|
497
|
+
'resources' => ['foods', '<food-id>'],
|
498
|
+
},
|
499
|
+
'api-get-food-goals' => {
|
500
|
+
'auth_required' => true,
|
501
|
+
'http_method' => 'get',
|
502
|
+
'resources' => ['user', '-', 'foods', 'log', 'goal'],
|
503
|
+
},
|
504
|
+
'api-get-foods' => {
|
505
|
+
'auth_required' => 'user-id',
|
506
|
+
'http_method' => 'get',
|
507
|
+
'request_headers' => ['Accept-Locale'],
|
508
|
+
'url_parameters' => ['date'],
|
509
|
+
'resources' => ['user', '-', 'foods', 'log', 'date', '<date>'],
|
510
|
+
},
|
511
|
+
'api-get-food-units' => {
|
512
|
+
'auth_required' => false,
|
513
|
+
'http_method' => 'get',
|
514
|
+
'request_headers' => ['Accept-Locale'],
|
515
|
+
'resources' => ['foods', 'units'],
|
516
|
+
},
|
517
|
+
'api-get-frequent-activities' => {
|
518
|
+
'auth_required' => true,
|
519
|
+
'http_method' => 'get',
|
520
|
+
'request_headers' => ['Accept-Locale', 'Accept-Language'],
|
521
|
+
'resources' => ['user', '-', 'activities', 'frequent'],
|
522
|
+
},
|
523
|
+
'api-get-frequent-foods' => {
|
524
|
+
'auth_required' => true,
|
525
|
+
'http_method' => 'get',
|
526
|
+
'request_headers' => ['Accept-Locale'],
|
527
|
+
'resources' => ['user', '-', 'foods', 'log', 'frequent'],
|
528
|
+
},
|
529
|
+
'api-get-friends' => {
|
530
|
+
'auth_required' => 'user-id',
|
531
|
+
'http_method' => 'get',
|
532
|
+
'request_headers' => ['Accept-Language'],
|
533
|
+
'resources' => ['user', '-', 'friends'],
|
534
|
+
},
|
535
|
+
'api-get-friends-leaderboard' => {
|
536
|
+
'auth_required' => true,
|
537
|
+
'http_method' => 'get',
|
538
|
+
'request_headers' => ['Accept-Language'],
|
539
|
+
'resources' => ['user', '-', 'friends', 'leaderboard'],
|
540
|
+
},
|
541
|
+
'api-get-glucose' => {
|
542
|
+
'auth_required' => true,
|
543
|
+
'http_method' => 'get',
|
544
|
+
'request_headers' => ['Accept-Language'],
|
545
|
+
'url_parameters' => ['date'],
|
546
|
+
'resources' => ['user', '-', 'glucose', 'date', '<date>'],
|
547
|
+
},
|
548
|
+
'api-get-heart-rate' => {
|
549
|
+
'auth_required' => true,
|
550
|
+
'http_method' => 'get',
|
551
|
+
'url_parameters' => ['date'],
|
552
|
+
'resources' => ['user', '-', 'heart', 'date', '<date>'],
|
553
|
+
},
|
554
|
+
'api-get-invites' => {
|
555
|
+
'auth_required' => true,
|
556
|
+
'http_method' => 'get',
|
557
|
+
'resources' => ['user', '-', 'friends', 'invitations'],
|
558
|
+
},
|
559
|
+
'api-get-meals' => {
|
560
|
+
'auth_required' => true,
|
561
|
+
'http_method' => 'get',
|
562
|
+
'request_headers' => ['Accept-Locale'],
|
563
|
+
'resources' => ['user', '-', 'meals'],
|
564
|
+
},
|
565
|
+
'api-get-recent-activities' => {
|
566
|
+
'auth_required' => true,
|
567
|
+
'http_method' => 'get',
|
568
|
+
'request_headers' => ['Accept-Locale', 'Accept-Language'],
|
569
|
+
'resources' => ['user', '-', 'activities', 'recent'],
|
570
|
+
},
|
571
|
+
'api-get-recent-foods' => {
|
572
|
+
'auth_required' => true,
|
573
|
+
'http_method' => 'get',
|
574
|
+
'request_headers' => ['Accept-Locale'],
|
575
|
+
'resources' => ['user', '-', 'foods', 'log', 'recent'],
|
576
|
+
},
|
577
|
+
'api-get-sleep' => {
|
578
|
+
'auth_required' => 'user-id',
|
579
|
+
'http_method' => 'get',
|
580
|
+
'url_parameters' => ['date'],
|
581
|
+
'resources' => ['user', '-', 'sleep', 'date', '<date>'],
|
582
|
+
},
|
583
|
+
'api-get-time-series' => {
|
584
|
+
'auth_required' => 'user-id',
|
585
|
+
'http_method' => 'get',
|
586
|
+
'request_headers' => ['Accept-Language'],
|
587
|
+
'url_parameters' => {
|
588
|
+
'end-date' => ['base-date', 'end-date', 'resource-path'],
|
589
|
+
'period' => ['base-date', 'period', 'resource-path'],
|
590
|
+
},
|
591
|
+
'resources' => {
|
592
|
+
'end-date' => ['user', '-', '<resource-path>', 'date', '<base-date>', '<end-date>'],
|
593
|
+
'period' => ['user', '-', '<resource-path>', 'date', '<base-date>', '<period>'],
|
594
|
+
},
|
595
|
+
},
|
596
|
+
'api-get-user-info' => {
|
597
|
+
'auth_required' => 'user-id',
|
598
|
+
'http_method' => 'get',
|
599
|
+
'request_headers' => ['Accept-Language'],
|
600
|
+
'resources' => ['user', '-', 'profile'],
|
601
|
+
},
|
602
|
+
'api-get-water' => {
|
603
|
+
'auth_required' => true,
|
604
|
+
'http_method' => 'get',
|
605
|
+
'request_headers' => ['Accept-Language'],
|
606
|
+
'url_parameters' => ['date'],
|
607
|
+
'resources' => ['user', '-', 'foods', 'log', 'water', 'date', '<date>'],
|
608
|
+
},
|
609
|
+
'api-log-activity' => {
|
610
|
+
'auth_required' => true,
|
611
|
+
'http_method' => 'post',
|
612
|
+
'post_parameters' => {
|
613
|
+
'exclusive' => ['activityId', 'activityName'],
|
614
|
+
'required' => ['startTime', 'durationMillis', 'date'],
|
615
|
+
'required_if' => { 'activityName' => 'manualCalories' },
|
616
|
+
},
|
617
|
+
'request_headers' => ['Accept-Locale', 'Accept-Language'],
|
618
|
+
'resources' => ['user', '-', 'activities'],
|
619
|
+
},
|
620
|
+
'api-log-blood-pressure' => {
|
621
|
+
'auth_required' => true,
|
622
|
+
'http_method' => 'post',
|
623
|
+
'post_parameters' => {
|
624
|
+
'required' => ['systolic', 'diastolic', 'date'],
|
625
|
+
},
|
626
|
+
'resources' => ['user', '-', 'bp'],
|
627
|
+
},
|
628
|
+
'api-log-body-fat' => {
|
629
|
+
'auth_required' => true,
|
630
|
+
'http_method' => 'post',
|
631
|
+
'post_parameters' => {
|
632
|
+
'required' => ['fat', 'date'],
|
633
|
+
},
|
634
|
+
'resources' => ['user', '-', 'body', 'log', 'fat'],
|
635
|
+
},
|
636
|
+
'api-log-body-measurements' => {
|
637
|
+
'auth_required' => true,
|
638
|
+
'http_method' => 'post',
|
639
|
+
'post_parameters' => {
|
640
|
+
'required' => ['date'],
|
641
|
+
'one_required' => ['bicep','calf','chest','fat','forearm','hips','neck','thigh','waist','weight'],
|
642
|
+
},
|
643
|
+
'request_headers' => ['Accept-Language'],
|
644
|
+
'resources' => ['user', '-', 'body'],
|
645
|
+
},
|
646
|
+
'api-log-body-weight' => {
|
647
|
+
'auth_required' => true,
|
648
|
+
'http_method' => 'post',
|
649
|
+
'post_parameters' => {
|
650
|
+
'required' => ['weight', 'date'],
|
651
|
+
},
|
652
|
+
'request_headers' => ['Accept-Language'],
|
653
|
+
'resources' => ['user', '-', 'body', 'log', 'weight'],
|
654
|
+
},
|
655
|
+
'api-log-food' => {
|
656
|
+
'auth_required' => true,
|
657
|
+
'http_method' => 'post',
|
658
|
+
'post_parameters' => {
|
659
|
+
'exclusive' => ['foodId', 'foodName'],
|
660
|
+
'required' => ['mealTypeId', 'unitId', 'amount', 'date'],
|
661
|
+
},
|
662
|
+
'request_headers' => ['Accept-Locale'],
|
663
|
+
'resources' => ['user', '-', 'foods', 'log'],
|
664
|
+
},
|
665
|
+
'api-log-glucose' => {
|
666
|
+
'auth_required' => true,
|
667
|
+
'http_method' => 'post',
|
668
|
+
'post_parameters' => {
|
669
|
+
'exclusive' => ['hbac1c', 'tracker'],
|
670
|
+
'required' => ['date'],
|
671
|
+
'required_if' => { 'tracker' => 'glucose' },
|
672
|
+
},
|
673
|
+
'request_headers' => ['Accept-Language'],
|
674
|
+
'resources' => ['user', '-', 'glucose'],
|
675
|
+
},
|
676
|
+
'api-log-heart-rate' => {
|
677
|
+
'auth_required' => true,
|
678
|
+
'http_method' => 'post',
|
679
|
+
'post_parameters' => {
|
680
|
+
'required' => ['tracker', 'heartRate', 'date'],
|
681
|
+
},
|
682
|
+
'resources' => ['user', '-', 'heart'],
|
683
|
+
},
|
684
|
+
'api-log-sleep' => {
|
685
|
+
'auth_required' => true,
|
686
|
+
'http_method' => 'post',
|
687
|
+
'post_parameters' => {
|
688
|
+
'required' => ['startTime', 'duration', 'date'],
|
689
|
+
},
|
690
|
+
'resources' => ['user', '-', 'sleep'],
|
691
|
+
},
|
692
|
+
'api-log-water' => {
|
693
|
+
'auth_required' => true,
|
694
|
+
'http_method' => 'post',
|
695
|
+
'post_parameters' => {
|
696
|
+
'required' => ['amount', 'date'],
|
697
|
+
},
|
698
|
+
'request_headers' => ['Accept-Language'],
|
699
|
+
'resources' => ['user', '-', 'foods', 'log', 'water'],
|
700
|
+
},
|
701
|
+
'api-search-foods' => {
|
702
|
+
'auth_required' => true,
|
703
|
+
'http_method' => 'get',
|
704
|
+
'request_headers' => ['Accept-Locale'],
|
705
|
+
'url_parameters' => ['query'],
|
706
|
+
'resources' => ['foods', 'search'],
|
707
|
+
},
|
708
|
+
'api-update-activity-daily-goals' => {
|
709
|
+
'auth_required' => true,
|
710
|
+
'http_method' => 'post',
|
711
|
+
'post_parameters' => {
|
712
|
+
'one_required' => ['caloriesOut','activeMinutes','floors','distance','steps'],
|
713
|
+
},
|
714
|
+
'request_headers' => ['Accept-Language'],
|
715
|
+
'resources' => ['user', '-', 'activities', 'goals', 'daily'],
|
716
|
+
},
|
717
|
+
'api-update-activity-weekly-goals' => {
|
718
|
+
'auth_required' => true,
|
719
|
+
'http_method' => 'post',
|
720
|
+
'post_parameters' => {
|
721
|
+
'one_required' => ['steps','distance','floors'],
|
722
|
+
},
|
723
|
+
'request_headers' => ['Accept-Language'],
|
724
|
+
'resources' => ['user', '-', 'activities', 'goals', 'weekly'],
|
725
|
+
},
|
726
|
+
'api-update-fat-goal' => {
|
727
|
+
'auth_required' => true,
|
728
|
+
'http_method' => 'post',
|
729
|
+
'post_parameters' => {
|
730
|
+
'required' => ['fat'],
|
731
|
+
},
|
732
|
+
'resources' => ['user', '-', 'body', 'log', 'fat', 'goal'],
|
733
|
+
},
|
734
|
+
'api-update-food-goals' => {
|
735
|
+
'auth_required' => true,
|
736
|
+
'http_method' => 'post',
|
737
|
+
'post_parameters' => {
|
738
|
+
'exclusive' => ['calories', 'intensity'],
|
739
|
+
},
|
740
|
+
'request_headers' => ['Accept-Locale', 'Accept-Language'],
|
741
|
+
'resources' => ['user', '-', 'foods', 'log', 'goal'],
|
742
|
+
},
|
743
|
+
'api-update-user-info' => {
|
744
|
+
'auth_required' => true,
|
745
|
+
'http_method' => 'post',
|
746
|
+
'post_parameters' => {
|
747
|
+
'one_required' => [
|
748
|
+
'gender','birthday','height','nickname','aboutMe','fullname','country','state','city',
|
749
|
+
'strideLengthWalking','strideLengthRunning','weightUnit','heightUnit','waterUnit','glucoseUnit',
|
750
|
+
'timezone','foodsLocale','locale','localeLang','localeCountry'
|
751
|
+
],
|
752
|
+
},
|
753
|
+
'request_headers' => ['Accept-Language'],
|
754
|
+
'resources' => ['user', '-', 'profile'],
|
755
|
+
},
|
756
|
+
'api-update-weight-goal' => {
|
757
|
+
'auth_required' => true,
|
758
|
+
'http_method' => 'post',
|
759
|
+
'post_parameters' => {
|
760
|
+
'required' => ['startDate', 'startWeight'],
|
761
|
+
},
|
762
|
+
'resources' => ['user', '-', 'body', 'log', 'weight', 'goal'],
|
763
|
+
},
|
764
|
+
}
|
765
|
+
|
766
|
+
end
|
767
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
require 'omniauth/strategies/oauth'
|
3
|
+
|
4
|
+
module OmniAuth
|
5
|
+
module Strategies
|
6
|
+
class Fitbit < OmniAuth::Strategies::OAuth
|
7
|
+
|
8
|
+
option :name, "fitbit"
|
9
|
+
|
10
|
+
option :client_options, {
|
11
|
+
:site => 'http://api.fitbit.com',
|
12
|
+
:request_token_path => '/oauth/request_token',
|
13
|
+
:access_token_path => '/oauth/access_token',
|
14
|
+
:authorize_path => '/oauth/authorize'
|
15
|
+
}
|
16
|
+
|
17
|
+
uid do
|
18
|
+
access_token.params['encoded_user_id']
|
19
|
+
end
|
20
|
+
|
21
|
+
info do
|
22
|
+
{
|
23
|
+
:full_name => raw_info['user']['fullName'],
|
24
|
+
:display_name => raw_info['user']['displayName'],
|
25
|
+
:nickname => raw_info['user']['nickname'],
|
26
|
+
:gender => raw_info['user']['gender'],
|
27
|
+
:about_me => raw_info['user']['aboutMe'],
|
28
|
+
:city => raw_info['user']['city'],
|
29
|
+
:state => raw_info['user']['state'],
|
30
|
+
:country => raw_info['user']['country'],
|
31
|
+
:dob => !raw_info['user']['dateOfBirth'].empty? ? Date.strptime(raw_info['user']['dateOfBirth'], '%Y-%m-%d'):nil,
|
32
|
+
:member_since => Date.strptime(raw_info['user']['memberSince'], '%Y-%m-%d'),
|
33
|
+
:locale => raw_info['user']['locale'],
|
34
|
+
:timezone => raw_info['user']['timezone']
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
extra do
|
39
|
+
{
|
40
|
+
:raw_info => raw_info
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def raw_info
|
45
|
+
@raw_info ||= MultiJson.load(access_token.get('http://api.fitbit.com/1/user/-/profile.json').body)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fitbit-omni-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TK Gospodinov
|
8
|
+
- Scott McGrath
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: omniauth-oauth
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: multi_xml
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
description: OmniAuth strategy for Fitbit, plus api wrapper
|
43
|
+
email:
|
44
|
+
- tk@gospodinov.net
|
45
|
+
- Scott McGrat
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- lib/api/fitbit_api.rb
|
51
|
+
- lib/fitbit-omni-api/version.rb
|
52
|
+
- lib/fitbit-omni-api.rb
|
53
|
+
- lib/omniauth/strategies/fitbit.rb
|
54
|
+
- LICENSE.md
|
55
|
+
- Rakefile
|
56
|
+
- README.md
|
57
|
+
homepage: http://github.com/scrawlon/fitbit-omni-api
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata: {}
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 2.0.3
|
78
|
+
signing_key:
|
79
|
+
specification_version: 4
|
80
|
+
summary: OmniAuth strategy for Fitbit, plus api wrapper
|
81
|
+
test_files: []
|