Files
Chad Whitacre 28cb48c72a Big changeover from id to username; #287
I sort of did this one with the blast shield down. I haven't even run
the tests yet. The sorts of things I changed:

 - SQL {elsewhere,exchanges}.participant_id => .participant
 - SQL participants.id => .username
 - ORM {user,participant,self}.id => .username
2013-04-05 15:48:59 -04:00

119 lines
3.8 KiB
Plaintext

"""Associate a Bitbucket account with a Gittip account.
First we do the OAuth dance with Bitbucket. Once we've authenticated the user
against Bitbucket, we record them in our elsewhere table. This table contains
information for Bitbucket users whether or not they are explicit participants in
the Gittip community.
"""
from urlparse import parse_qs
import requests
from oauth_hook import OAuthHook
from aspen import log, Response, json
from aspen import resources
from gittip.elsewhere import ACTIONS, bitbucket
from gittip.participant import NeedConfirmation
# ========================== ^L
if 'denied' in qs:
request.redirect('/')
token = qs['oauth_token']
try:
secret, action, then = website.oauth_cache.pop(token)
except KeyError:
request.redirect("/about/me.html")
oauth_hook = OAuthHook( token
, secret
, header_auth=True
, consumer_key=website.bitbucket_consumer_key
, consumer_secret=website.bitbucket_consumer_secret
)
response = requests.post( "https://bitbucket.org/api/1.0/oauth/access_token"
, data={"oauth_verifier": qs['oauth_verifier']}
, hooks={'pre_request': oauth_hook}
)
assert response.status_code == 200, response.status_code
reply = parse_qs(response.text)
token = reply['oauth_token'][0]
secret = reply['oauth_token_secret'][0]
oauth_hook = OAuthHook( token # XXX really instantiate again?
, secret
, header_auth=True
, consumer_key=website.bitbucket_consumer_key
, consumer_secret=website.bitbucket_consumer_secret
)
response = requests.get( "https://bitbucket.org/api/1.0/user"
, hooks={'pre_request': oauth_hook}
)
user_info = json.loads(response.text)['user']
assert response.status_code == 200, response.status_code
# Load Bitbucket user info.
if action not in ACTIONS:
raise Response(400)
# Make sure we have a Bitbucket username.
username = user_info.get('username')
if username is None:
log(u"We got a user_info from Bitbucket with no username [%s, %s]"
% (action, then))
raise Response(400)
assert 'html_url' not in user_info
user_info['html_url'] = "https://bitbucket.org/" + username
# Do something.
log(u"%s wants to %s" % (username, action))
account = bitbucket.BitbucketAccount(username, user_info)
if action == 'opt-in': # opt in
user = account.opt_in(username) # set 'user' to give them a session :/
elif action == 'connect': # connect
if user.ANON:
raise Response(404)
try:
user.take_over(account)
except NeedConfirmation, obstacles:
# XXX Eep! Internal redirect! Really?!
request.internally_redirected_from = request.fs
request.fs = website.www_root + '/on/confirm.html'
request.resource = resources.get(request)
raise request.resource.respond(request)
else: # lock or unlock
if then != username:
# The user could spoof `then' to match their username, but the most
# they can do is lock/unlock their own Bitbucket account in a convoluted
# way.
then = u'/on/bitbucket/%s/lock-fail.html' % then
else:
# Associate the Bitbucket username with a randomly-named, unclaimed
# Gittip participant.
assert account.participant != username, username # sanity check
account.set_is_locked(action == 'lock')
if then == u'':
then = u'/%s/' % account.participant
if not then.startswith(u'/'):
# Interpret it as a Bitbucket username.
then = u'/on/bitbucket/%s/' % then
request.redirect(then)
# ========================== ^L text/plain