From: Larry Price Date: Fri, 24 Feb 2012 08:41:16 +0000 (-0800) Subject: replaced with a version based on the flickr backend. Works for basic functionality. X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=4db2a390ea9ea73f3f3e0b8d4d3da755f8bbdb02;p=django-social-auth.git replaced with a version based on the flickr backend. Works for basic functionality. --- diff --git a/social_auth/backends/contrib/fitbit.py b/social_auth/backends/contrib/fitbit.py index ae78f2a..5084fa6 100644 --- a/social_auth/backends/contrib/fitbit.py +++ b/social_auth/backends/contrib/fitbit.py @@ -5,31 +5,27 @@ This contribution adds support for Fitbit OAuth service. The settings FITBIT_CONSUMER_KEY and FITBIT_CONSUMER_SECRET must be defined with the values given by Fitbit application registration process. -Extended permissions are supported by defining FITBIT_EXTENDED_PERMISSIONS -setting, it must be a list of values to request. - -By default account id and token expiration time are stored in extra_data -field, check OAuthBackend class for details on how to extend it. +By default account id, username and token expiration time are stored in +extra_data field, check OAuthBackend class for details on how to extend it. """ -import logging -logger = logging.getLogger('buttekicker') - -import cgi -import urllib +try: + from urlparse import parse_qs + parse_qs # placate pyflakes +except ImportError: + # fall back for Python 2.5 + from cgi import parse_qs from django.conf import settings from django.utils import simplejson -from django.contrib.auth import authenticate - -from social_auth.backends import BaseOAuth, OAuthBackend, USERNAME +from oauth2 import Token +from social_auth.backends import ConsumerBasedOAuth, OAuthBackend, USERNAME # Fitbit configuration -FITBIT_SERVER = 'api.fitbit.com' -FITBIT_REQUEST_TOKEN_URL = 'https://%s/oauth/request_token' % FITBIT_SERVER -FITBIT_AUTHORIZATION_URL = 'https://%s/oauth/authorize' % FITBIT_SERVER -FITBIT_ACCESS_TOKEN_URL = 'https://%s/oauth/access_token' % FITBIT_SERVER -FITBIT_API_URL = 'https://api.%s' % FITBIT_SERVER +FITBIT_SERVER = 'https://api.fitbit.com' +FITBIT_REQUEST_TOKEN_URL = '%s/oauth/request_token' % FITBIT_SERVER +FITBIT_AUTHORIZATION_URL = '%s/oauth/authorize' % FITBIT_SERVER +FITBIT_ACCESS_TOKEN_URL = '%s/oauth/access_token' % FITBIT_SERVER EXPIRES_NAME = getattr(settings, 'SOCIAL_AUTH_EXPIRATION', 'expires') @@ -37,67 +33,52 @@ class FitbitBackend(OAuthBackend): """Fitbit OAuth authentication backend""" name = 'fitbit' # Default extra data to store - EXTRA_DATA = [('id', 'id'), ('expires', EXPIRES_NAME)] + EXTRA_DATA = [('id', 'id'), + ('username', 'username'), + ('expires', EXPIRES_NAME)] def get_user_details(self, response): """Return user details from Fitbit account""" - return {USERNAME: response.get('login'), - 'email': response.get('email') or '', - 'first_name': response.get('name')} + return {USERNAME: response.get('id'), + 'email': '', + 'first_name': response.get('fullname')} -class FitbitAuth(BaseOAuth): - """Fitbit OAuth mechanism""" - AUTH_BACKEND = FitbitBackend - def auth_url(self): - """Returns redirect url""" - args = {'client_id': settings.FITBIT_CONSUMER_KEY, - 'redirect_uri': self.redirect_uri} - if hasattr(settings, 'FITBIT_EXTENDED_PERMISSIONS'): - args['scope'] = ','.join(settings.FITBIT_EXTENDED_PERMISSIONS) - args.update(self.auth_extra_arguments()) - return FITBIT_AUTHORIZATION_URL + '?' + urllib.urlencode(args) - - def auth_complete(self, *args, **kwargs): - """Returns user, might be logged in""" - if 'code' in self.data: - url = FITBIT_ACCESS_TOKEN_URL + '?' + \ - urllib.urlencode({'client_id': settings.FITBIT_CONSUMER_KEY, - 'redirect_uri': self.redirect_uri, - 'client_secret': settings.FITBIT_CONSUMER_SECRET, - 'code': self.data['code']}) - response = cgi.parse_qs(urllib.urlopen(url).read()) - if response.get('error'): - error = self.data.get('error') or 'unknown error' - raise ValueError('Authentication error: %s' % error) - access_token = response['access_token'][0] - data = self.user_data(access_token) - if data is not None: - if 'error' in data: - error = self.data.get('error') or 'unknown error' - raise ValueError('Authentication error: %s' % error) - data['access_token'] = access_token - kwargs.update({'response': data, FitbitBackend.name: True}) - return authenticate(*args, **kwargs) - else: - error = self.data.get('error') or 'unknown error' - raise ValueError('Authentication error: %s' % error) +class FitbitAuth(ConsumerBasedOAuth): + """Fitbit OAuth authentication mechanism""" + AUTHORIZATION_URL = FITBIT_AUTHORIZATION_URL + REQUEST_TOKEN_URL = FITBIT_REQUEST_TOKEN_URL + ACCESS_TOKEN_URL = FITBIT_ACCESS_TOKEN_URL + SERVER_URL = FITBIT_SERVER + AUTH_BACKEND = FitbitBackend + SETTINGS_KEY_NAME = 'FITBIT_CONSUMER_KEY' + SETTINGS_SECRET_NAME = 'FITBIT_CONSUMER_SECRET' + + def access_token(self, token): + """Return request for access token value""" + # Fitbit is a bit different - it passes user information along with + # the access token, so temporarily store it to vie the user_data + # method easy access later in the flow! + request = self.oauth_request(token, self.ACCESS_TOKEN_URL) + response = self.fetch_response(request) + token = Token.from_string(response) + params = parse_qs(response) + + token.user_nsid = params['user_nsid'][0] if 'user_nsid' in params \ + else None + token.fullname = params['fullname'][0] if 'fullname' in params \ + else None + token.username = params['username'][0] if 'username' in params \ + else None + return token def user_data(self, access_token): """Loads user data from service""" - params = {'access_token': access_token} - url = FITBIT_API_URL + '/user?' + urllib.urlencode(params) - try: - return simplejson.load(urllib.urlopen(url)) - except ValueError: - return None - - @classmethod - def enabled(cls): - """Return backend enabled status by checking basic settings""" - return all(hasattr(settings, name) for name in - ('FITBIT_CONSUMER_KEY', - 'FITBIT_CONSUMER_SECRET')) + return { + 'id': access_token.user_nsid, + 'username': access_token.username, + 'fullname': access_token.fullname, + } # Backend definition