Skip to content

Commit 366f70d

Browse files
committed
Merge pull request #85 from orcasgit/oauth2-support-only
OAuth2 support only
2 parents d6454f8 + ee9cef6 commit 366f70d

File tree

13 files changed

+64
-357
lines changed

13 files changed

+64
-357
lines changed

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ env:
77
- TOX_ENV=py35
88
- TOX_ENV=py34
99
- TOX_ENV=py33
10-
- TOX_ENV=py32
1110
- TOX_ENV=py27
12-
- TOX_ENV=py26
1311
- TOX_ENV=docs
1412
install:
1513
- pip install coveralls tox

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
0.2 (2016-03-23)
2+
================
3+
4+
* Drop OAuth1 support. See `OAuth1 deprecated <https://dev.fitbit.com/docs/oauth2/#oauth-1-0a-deprecated>`_
5+
* Drop py26 and py32 support
6+
17
0.1.3 (2015-02-04)
28
==================
39

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ For documentation: `http://python-fitbit.readthedocs.org/ <http://python-fitbit.
1818
Requirements
1919
============
2020

21-
* Python 2.6+
21+
* Python 2.7+
2222
* `python-dateutil`_ (always)
2323
* `requests-oauthlib`_ (always)
2424
* `Sphinx`_ (to create the documention)

docs/index.rst

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,11 @@ If you are only retrieving data that doesn't require authorization, then you can
2121
# certain methods do not require user keys
2222
unauth_client.food_units()
2323

24-
Here is an example of authorizing with OAuth 1.0::
25-
26-
# You'll have to gather the user keys on your own, or try
27-
# ./gather_keys_cli.py <consumer_key> <consumer_secret> for development
28-
authd_client = fitbit.Fitbit('<consumer_key>', '<consumer_secret>', resource_owner_key='<user_key>', resource_owner_secret='<user_secret>')
29-
authd_client.sleep()
30-
3124
Here is an example of authorizing with OAuth 2.0::
3225

3326
# You'll have to gather the tokens on your own, or use
3427
# ./gather_keys_oauth2.py
35-
authd_client = fitbit.Fitbit('<consumer_key>', '<consumer_secret>', oauth2=True,
28+
authd_client = fitbit.Fitbit('<consumer_key>', '<consumer_secret>',
3629
access_token='<access_token>', refresh_token='<refresh_token>')
3730
authd_client.sleep()
3831

fitbit/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
:license: BSD, see LICENSE for more details.
88
"""
99

10-
from .api import Fitbit, FitbitOauthClient, FitbitOauth2Client
10+
from .api import Fitbit, FitbitOauth2Client
1111

1212
# Meta.
1313

@@ -17,8 +17,8 @@
1717
__copyright__ = 'Copyright 2012-2015 ORCAS'
1818
__license__ = 'Apache 2.0'
1919

20-
__version__ = '0.1.3'
21-
__release__ = '0.1.3'
20+
__version__ = '0.2'
21+
__release__ = '0.2'
2222

2323
# Module namespace.
2424

fitbit/api.py

Lines changed: 5 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# Python 2.x
1111
from urllib import urlencode
1212

13-
from requests_oauthlib import OAuth1, OAuth1Session, OAuth2, OAuth2Session
13+
from requests_oauthlib import OAuth2, OAuth2Session
1414
from oauthlib.oauth2 import TokenExpiredError
1515
from fitbit.exceptions import (BadResponse, DeleteError, HTTPBadRequest,
1616
HTTPUnauthorized, HTTPForbidden,
@@ -19,130 +19,6 @@
1919
from fitbit.utils import curry
2020

2121

22-
class FitbitOauthClient(object):
23-
API_ENDPOINT = "https://api.fitbit.com"
24-
AUTHORIZE_ENDPOINT = "https://www.fitbit.com"
25-
API_VERSION = 1
26-
27-
request_token_url = "%s/oauth/request_token" % API_ENDPOINT
28-
access_token_url = "%s/oauth/access_token" % API_ENDPOINT
29-
authorization_url = "%s/oauth/authorize" % AUTHORIZE_ENDPOINT
30-
31-
def __init__(self, client_key, client_secret, resource_owner_key=None,
32-
resource_owner_secret=None, user_id=None, callback_uri=None,
33-
*args, **kwargs):
34-
"""
35-
Create a FitbitOauthClient object. Specify the first 5 parameters if
36-
you have them to access user data. Specify just the first 2 parameters
37-
to access anonymous data and start the set up for user authorization.
38-
39-
Set callback_uri to a URL and when the user has granted us access at
40-
the fitbit site, fitbit will redirect them to the URL you passed. This
41-
is how we get back the magic verifier string from fitbit if we're a web
42-
app. If we don't pass it, then fitbit will just display the verifier
43-
string for the user to copy and we'll have to ask them to paste it for
44-
us and read it that way.
45-
"""
46-
47-
self.session = requests.Session()
48-
self.client_key = client_key
49-
self.client_secret = client_secret
50-
self.resource_owner_key = resource_owner_key
51-
self.resource_owner_secret = resource_owner_secret
52-
if user_id:
53-
self.user_id = user_id
54-
params = {'client_secret': client_secret}
55-
if callback_uri:
56-
params['callback_uri'] = callback_uri
57-
if self.resource_owner_key and self.resource_owner_secret:
58-
params['resource_owner_key'] = self.resource_owner_key
59-
params['resource_owner_secret'] = self.resource_owner_secret
60-
self.oauth = OAuth1Session(client_key, **params)
61-
62-
def _request(self, method, url, **kwargs):
63-
"""
64-
A simple wrapper around requests.
65-
"""
66-
return self.session.request(method, url, **kwargs)
67-
68-
def make_request(self, url, data={}, method=None, **kwargs):
69-
"""
70-
Builds and makes the OAuth Request, catches errors
71-
72-
https://wiki.fitbit.com/display/API/API+Response+Format+And+Errors
73-
"""
74-
if not method:
75-
method = 'POST' if data else 'GET'
76-
auth = OAuth1(
77-
self.client_key, self.client_secret, self.resource_owner_key,
78-
self.resource_owner_secret, signature_type='auth_header')
79-
response = self._request(method, url, data=data, auth=auth, **kwargs)
80-
81-
if response.status_code == 401:
82-
raise HTTPUnauthorized(response)
83-
elif response.status_code == 403:
84-
raise HTTPForbidden(response)
85-
elif response.status_code == 404:
86-
raise HTTPNotFound(response)
87-
elif response.status_code == 409:
88-
raise HTTPConflict(response)
89-
elif response.status_code == 429:
90-
exc = HTTPTooManyRequests(response)
91-
exc.retry_after_secs = int(response.headers['Retry-After'])
92-
raise exc
93-
94-
elif response.status_code >= 500:
95-
raise HTTPServerError(response)
96-
elif response.status_code >= 400:
97-
raise HTTPBadRequest(response)
98-
return response
99-
100-
def fetch_request_token(self):
101-
"""
102-
Step 1 of getting authorized to access a user's data at fitbit: this
103-
makes a signed request to fitbit to get a token to use in step 3.
104-
Returns that token.}
105-
"""
106-
107-
token = self.oauth.fetch_request_token(self.request_token_url)
108-
self.resource_owner_key = token.get('oauth_token')
109-
self.resource_owner_secret = token.get('oauth_token_secret')
110-
return token
111-
112-
def authorize_token_url(self, **kwargs):
113-
"""Step 2: Return the URL the user needs to go to in order to grant us
114-
authorization to look at their data. Then redirect the user to that
115-
URL, open their browser to it, or tell them to copy the URL into their
116-
browser. Allow the client to request the mobile display by passing
117-
the display='touch' argument.
118-
"""
119-
120-
return self.oauth.authorization_url(self.authorization_url, **kwargs)
121-
122-
def fetch_access_token(self, verifier, token=None):
123-
"""Step 3: Given the verifier from fitbit, and optionally a token from
124-
step 1 (not necessary if using the same FitbitOAuthClient object) calls
125-
fitbit again and returns an access token object. Extract the needed
126-
information from that and save it to use in future API calls.
127-
"""
128-
if token:
129-
self.resource_owner_key = token.get('oauth_token')
130-
self.resource_owner_secret = token.get('oauth_token_secret')
131-
132-
self.oauth = OAuth1Session(
133-
self.client_key,
134-
client_secret=self.client_secret,
135-
resource_owner_key=self.resource_owner_key,
136-
resource_owner_secret=self.resource_owner_secret,
137-
verifier=verifier)
138-
response = self.oauth.fetch_access_token(self.access_token_url)
139-
140-
self.user_id = response.get('encoded_user_id')
141-
self.resource_owner_key = response.get('oauth_token')
142-
self.resource_owner_secret = response.get('oauth_token_secret')
143-
return response
144-
145-
14622
class FitbitOauth2Client(object):
14723
API_ENDPOINT = "https://api.fitbit.com"
14824
AUTHORIZE_ENDPOINT = "https://www.fitbit.com"
@@ -205,7 +81,7 @@ def make_request(self, url, data={}, method=None, **kwargs):
20581
try:
20682
if(d['errors'][0]['errorType'] == 'oauth' and
20783
d['errors'][0]['fieldName'] == 'access_token' and
208-
d['errors'][0]['message'].find('Access token invalid or expired:')==0):
84+
d['errors'][0]['message'].find('Access token invalid or expired:') == 0):
20985
self.refresh_token()
21086
auth = OAuth2(client_id=self.client_id, token=self.token)
21187
response = self._request(method, url, data=data, auth=auth, **kwargs)
@@ -322,17 +198,12 @@ class Fitbit(object):
322198
'frequent',
323199
]
324200

325-
def __init__(self, client_key, client_secret, oauth2=False, system=US, **kwargs):
201+
def __init__(self, client_id, client_secret, system=US, **kwargs):
326202
"""
327-
oauth1: Fitbit(<key>, <secret>, resource_owner_key=<key>, resource_owner_secret=<key>)
328-
oauth2: Fitbit(<id>, <secret>, oauth2=True, access_token=<token>, refresh_token=<token>)
203+
Fitbit(<id>, <secret>, access_token=<token>, refresh_token=<token>)
329204
"""
330205
self.system = system
331-
332-
if oauth2:
333-
self.client = FitbitOauth2Client(client_key, client_secret, **kwargs)
334-
else:
335-
self.client = FitbitOauthClient(client_key, client_secret, **kwargs)
206+
self.client = FitbitOauth2Client(client_id, client_secret, **kwargs)
336207

337208
# All of these use the same patterns, define the method for accessing
338209
# creating and deleting records once, and use curry to make individual
@@ -1114,10 +985,3 @@ def list_subscriptions(self, collection=''):
1114985
collection='/{0}'.format(collection) if collection else ''
1115986
)
1116987
return self.make_request(url)
1117-
1118-
@classmethod
1119-
def from_oauth_keys(self, client_key, client_secret, user_key=None,
1120-
user_secret=None, user_id=None, system=US):
1121-
client = FitbitOauthClient(client_key, client_secret, user_key,
1122-
user_secret, user_id)
1123-
return self(client, system)

fitbit_tests/__init__.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
22
from .test_exceptions import ExceptionTest
3-
from .test_auth import AuthTest, Auth2Test
3+
from .test_auth import Auth2Test
44
from .test_api import (
55
APITest,
66
CollectionResourceTest,
@@ -12,15 +12,8 @@
1212

1313

1414
def all_tests(consumer_key="", consumer_secret="", user_key=None, user_secret=None):
15-
kwargs = {
16-
"consumer_key": consumer_key,
17-
"consumer_secret": consumer_secret,
18-
"user_key": user_key,
19-
"user_secret": user_secret,
20-
}
2115
suite = unittest.TestSuite()
2216
suite.addTest(unittest.makeSuite(ExceptionTest))
23-
suite.addTest(unittest.makeSuite(AuthTest))
2417
suite.addTest(unittest.makeSuite(Auth2Test))
2518
suite.addTest(unittest.makeSuite(APITest))
2619
suite.addTest(unittest.makeSuite(CollectionResourceTest))

0 commit comments

Comments
 (0)