class Facebook(PlatformOAuth2): # Platform attributes name = 'facebook' display_name = 'Facebook' account_url = 'https://www.facebook.com/{user_name}' # Auth attributes auth_url = 'https://www.facebook.com/dialog/oauth' access_token_url = 'https://graph.facebook.com/oauth/access_token' oauth_default_scope = ['public_profile,email'] # API attributes api_format = 'json' api_url = 'https://graph.facebook.com' api_user_info_path = '/{user_name}' api_user_self_info_path = '/me' # User info extractors x_user_id = key('id') x_user_name = key('username') x_display_name = key('name') x_email = key('email') def x_avatar_url(self, extracted, info, default): picture = self.api_get('/' + extracted.user_name + '/picture' '?redirect=false&width=256&height=256') data = picture.json().get('data', {}) avatar_url = data.get('url') if data.get('is_silhouette'): avatar_url = None return avatar_url
class Twitter(PlatformOAuth1): # Platform attributes name = 'twitter' display_name = 'Twitter' account_url = 'https://twitter.com/{user_name}' # Auth attributes auth_url = 'https://api.twitter.com' authorize_path = '/oauth/authenticate' # API attributes api_format = 'json' api_paginator = query_param_paginator('cursor', prev='previous_cursor', next='next_cursor') api_url = 'https://api.twitter.com/1.1' api_user_info_path = '/users/show.json?user_id={user_id}' api_user_name_info_path = '/users/show.json?screen_name={user_name}' api_user_self_info_path = '/account/verify_credentials.json' api_friends_path = '/friends/list.json?user_id={user_id}&skip_status=true' ratelimit_headers_prefix = 'x-rate-limit-' # User info extractors x_user_id = key('id') x_user_name = key('screen_name') x_display_name = key('name') x_email = not_available x_avatar_url = key('profile_image_url_https', clean=lambda v: v.replace('_normal.', '.')) x_friends_count = key('friends_count')
class Twitter(PlatformOAuth1): # Platform attributes name = 'twitter' display_name = 'Twitter' account_url = 'https://twitter.com/{user_name}' # Auth attributes auth_url = 'https://api.twitter.com' authorize_path = '/oauth/authenticate' # API attributes api_format = 'json' api_url = 'https://api.twitter.com/1.1' api_user_info_path = '/users/show.json?screen_name={user_name}' api_user_self_info_path = '/account/verify_credentials.json' ratelimit_headers_prefix = 'x-rate-limit-' # User info extractors x_user_id = key('id') x_user_name = key('screen_name') x_display_name = key('name') x_email = not_available x_avatar_url = key('profile_image_url_https', clean=lambda v: v.replace('_normal.', '.'))
class Google(PlatformOAuth2): # Platform attributes name = 'google' display_name = 'Google' account_url = 'https://plus.google.com/{user_id}' # Auth attributes auth_url = 'https://accounts.google.com/o/oauth2/auth' access_token_url = 'https://accounts.google.com/o/oauth2/token' oauth_default_scope = [ 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile' ] # API attributes api_format = 'json' api_url = 'https://www.googleapis.com/plus/v1' api_user_info_path = '/people/{user_id}' api_user_self_info_path = '/people/me' # User info extractors x_user_id = key('id') x_display_name = key('displayName') x_email = any_key(('emails', 0), clean=lambda d: d.get('value')) x_avatar_url = key('image', clean=lambda d: d.get('url')) def x_user_name(self, extracted, info, *default): url = info.get('url', '') return url[25:] if url.startswith( 'https://plus.google.com/+') else None
class Facebook(PlatformOAuth2): # Platform attributes name = 'facebook' display_name = 'Facebook' account_url = 'https://www.facebook.com/profile.php?id={user_id}' # Auth attributes auth_url = 'https://www.facebook.com/dialog/oauth' access_token_url = 'https://graph.facebook.com/oauth/access_token' oauth_default_scope = ['public_profile,email'] # API attributes api_format = 'json' api_url = 'https://graph.facebook.com' api_user_info_path = '/{user_name}' api_user_self_info_path = '/me' # User info extractors x_user_id = key('id') x_user_name = key('username') x_display_name = key('name') x_email = key('email') def x_avatar_url(self, extracted, info, default): return 'https://graph.facebook.com/' + extracted.user_id + '/picture?width=256&height=256'
class Bitbucket(PlatformOAuth1): # Platform attributes name = 'bitbucket' display_name = 'Bitbucket' account_url = 'https://bitbucket.org/{user_name}' # Auth attributes auth_url = 'https://bitbucket.org/api/1.0' authorize_path = '/oauth/authenticate' # API attributes api_format = 'json' api_paginator = keys_paginator(prev='previous') api_url = 'https://bitbucket.org/api' api_user_info_path = '/1.0/users/{user_name}' api_user_self_info_path = '/1.0/user' api_team_members_path = '/2.0/teams/{user_name}/members' # User info extractors x_user_info = key('user') x_user_id = not_available # No immutable id. :-/ x_user_name = key('username') x_display_name = key('display_name') x_email = not_available x_avatar_url = any_key('avatar', ('links', 'avatar', 'href')) x_is_team = key('is_team')
class Facebook(PlatformOAuth2): # Platform attributes name = 'facebook' display_name = 'Facebook' account_url = 'https://www.facebook.com/profile.php?id={user_id}' optional_user_name = True # Auth attributes auth_url = 'https://www.facebook.com/dialog/oauth' access_token_url = 'https://graph.facebook.com/oauth/access_token' oauth_default_scope = ['public_profile,email,user_friends'] # API attributes api_format = 'json' api_paginator = keys_paginator('data', paging='paging', prev='previous') api_url = 'https://graph.facebook.com' api_user_name_info_path = '/{user_name}' api_user_self_info_path = '/me' api_friends_path = '/v2.2/{user_id}/friends' api_friends_limited = True # User info extractors x_user_id = key('id') x_user_name = key('username') x_display_name = key('name') x_email = key('email') def x_avatar_url(self, extracted, info, default): return 'https://graph.facebook.com/' + extracted.user_id + '/picture?width=256&height=256'
class Bountysource(Platform): # Platform attributes name = 'bountysource' display_name = 'Bountysource' account_url = '{platform_data.auth_url}/people/{user_id}' optional_user_name = True # API attributes api_format = 'json' api_user_info_path = '/users/{user_id}' api_user_self_info_path = '/user' # User info extractors x_user_id = key('id') x_user_name = not_available x_display_name = key('display_name') x_email = key('email') x_avatar_url = key('image_url') def get_auth_session(self, token=None): sess = requests.Session() sess.auth = BountysourceAuth(token) return sess def get_auth_url(self, user): query_id = hexlify(os.urandom(10)) time_now = int(time()) raw = '%s.%s.%s' % (user.participant.id, time_now, self.api_secret) h = hashlib.md5(raw).hexdigest() token = '%s.%s.%s' % (user.participant.id, time_now, h) params = dict(redirect_url=self.callback_url + '?query_id=' + query_id, external_access_token=token) url = self.auth_url + '/auth/gratipay/confirm?' + urlencode(params) return url, query_id, '' def get_query_id(self, querystring): token = querystring['access_token'] i = token.rfind('.') data, data_hash = token[:i], token[i + 1:] if data_hash != hashlib.md5(data + '.' + self.api_secret).hexdigest(): raise Response(400, 'Invalid hash in access_token') return querystring['query_id'] def get_user_self_info(self, sess): querystring = urlparse(sess._callback_url).query info = { k: v[0] if len(v) == 1 else v for k, v in parse_qs(querystring).items() } info.pop('access_token') info.pop('query_id') return self.extract_user_info(info) def handle_auth_callback(self, url, query_id, unused_arg): sess = self.get_auth_session(token=query_id) sess._callback_url = url return sess
class Bitbucket(PlatformOAuth1): # Platform attributes name = 'bitbucket' display_name = 'Bitbucket' account_url = 'https://bitbucket.org/{user_name}' # Auth attributes auth_url = 'https://bitbucket.org/api/1.0' authorize_path = '/oauth/authenticate' # API attributes api_format = 'json' api_paginator = keys_paginator('values', prev='previous', total='size') api_url = 'https://bitbucket.org/api' api_user_info_path = '/2.0/users/{user_id}' api_user_name_info_path = '/2.0/users/{user_name}' api_user_self_info_path = '/2.0/user' api_team_members_path = '/2.0/teams/{user_name}/members' api_friends_path = '/2.0/users/{user_name}/following' # User info extractors x_user_info = key('user') x_user_id = key('uuid') x_user_name = key('username') x_display_name = key('display_name') x_email = not_available x_avatar_url = any_key('avatar', ('links', 'avatar', 'href')) x_is_team = key('type', lambda v: v == 'team') def api_get(self, path, sess=None, **kw): """Extend to manually retry /users/pypy as /teams/pypy. Bitbucket gives us a 404 where a 30x would be more helpful. """ try: return PlatformOAuth1.api_get(self, path, sess, **kw) except Response, response: if response.code == 404 and ' is a team account' in response.body: assert path.startswith('/2.0/users/') path = '/2.0/teams/' + path[11:] return PlatformOAuth1.api_get(self, path, sess, **kw) else: raise
class Venmo(PlatformOAuth2): # Platform attributes name = 'venmo' display_name = 'Venmo' account_url = 'https://venmo.com/{user_name}' # PlatformOAuth2 attributes auth_url = 'https://api.venmo.com/v1/oauth/authorize' access_token_url = 'https://api.venmo.com/v1/oauth/access_token' oauth_email_scope = 'access_email' oauth_payment_scope = 'make_payments' oauth_default_scope = ['access_profile'] # API attributes api_format = 'json' api_url = 'https://api.venmo.com/v1' api_user_info_path = '/users/{user_id}' api_user_self_info_path = '/me' # User info extractors x_user_info = key('data', clean=lambda d: d.pop('user', d)) x_user_id = key('id') x_user_name = key('username') x_display_name = key('display_name') x_email = key('email') x_avatar_url = key('profile_picture_url')
class GitHub(PlatformOAuth2): # Platform attributes name = 'github' display_name = 'GitHub' account_url = 'https://github.com/{user_name}' allows_team_connect = True # Auth attributes auth_url = 'https://github.com/login/oauth/authorize' access_token_url = 'https://github.com/login/oauth/access_token' oauth_email_scope = 'user:email' oauth_default_scope = ['read:org'] # API attributes api_format = 'json' api_paginator = header_links_paginator() api_url = 'https://api.github.com' api_user_info_path = '/user/{user_id}' api_user_name_info_path = '/users/{user_name}' api_user_self_info_path = '/user' api_team_members_path = '/orgs/{user_name}/public_members' api_friends_path = '/users/{user_name}/following' ratelimit_headers_prefix = 'x-ratelimit-' # User info extractors x_user_id = key('id') x_user_name = key('login') x_display_name = key('name') x_email = key('email') x_gravatar_id = key('gravatar_id') x_avatar_url = key('avatar_url') x_is_team = key('type', clean=lambda t: t.lower() == 'organization') def is_team_admin(self, team_name, sess): user_teams = self.api_parser(self.api_get('/user/teams', sess=sess)) return any(team.get('organization', {}).get('login') == team_name and team.get('permission') == 'admin' for team in user_teams)