This repository has been archived by the owner on Feb 8, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Can now tip to a Twitter user! (#80)
- Loading branch information
1 parent
3755332
commit bf849a0
Showing
5 changed files
with
218 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import requests | ||
from aspen import json, log, Response | ||
from aspen.website import Website | ||
from aspen.utils import typecheck | ||
from gittip import db, networks | ||
|
||
|
||
def upsert(user_info): | ||
return networks.upsert( 'twitter' | ||
, user_info['id'] | ||
, user_info['screen_name'] | ||
, user_info | ||
) | ||
|
||
|
||
def oauth_url(website, action, then=u""): | ||
"""Given a website object and a string, return a URL string. | ||
`action' is one of 'opt-in', 'lock' and 'unlock' | ||
`then' is either a twitter username or an URL starting with '/'. It's | ||
where we'll send the user after we get the redirect back from | ||
GitHub. | ||
""" | ||
typecheck(website, Website, action, unicode, then, unicode) | ||
assert action in [u'opt-in', u'lock', u'unlock'] | ||
url = u"https://twitter.com/login/oauth/authorize?consumer_key=%s&redirect_uri=%s" | ||
url %= (website.twitter_consumer_key, website.twitter_callback) | ||
|
||
# Pack action,then into data and base64-encode. Querystring isn't | ||
# available because it's consumed by the initial GitHub request. | ||
|
||
data = u'%s,%s' % (action, then) | ||
data = data.encode('UTF-8').encode('base64').decode('US-ASCII') | ||
url += u'?data=%s' % data | ||
return url | ||
|
||
|
||
def oauth_dance(website, qs): | ||
"""Given a querystring, return a dict of user_info. | ||
The querystring should be the querystring that we get from GitHub when | ||
we send the user to the return value of oauth_url above. | ||
See also: | ||
http://developer.twitter.com/v3/oauth/ | ||
""" | ||
|
||
log("Doing an OAuth dance with Github.") | ||
|
||
if 'error' in qs: | ||
raise Response(500, str(qs['error'])) | ||
|
||
data = { 'code': qs['code'].encode('US-ASCII') | ||
, 'client_id': website.twitter_client_id | ||
, 'client_secret': website.twitter_client_secret | ||
} | ||
r = requests.post("https://twitter.com/login/oauth/access_token", data=data) | ||
assert r.status_code == 200, (r.status_code, r.text) | ||
|
||
back = dict([pair.split('=') for pair in r.text.split('&')]) # XXX | ||
if 'error' in back: | ||
raise Response(400, back['error'].encode('utf-8')) | ||
assert back.get('token_type', '') == 'bearer', back | ||
access_token = back['access_token'] | ||
|
||
r = requests.get( "https://api.twitter.com/user" | ||
, headers={'Authorization': 'token %s' % access_token} | ||
) | ||
assert r.status_code == 200, (r.status_code, r.text) | ||
user_info = json.loads(r.text) | ||
log("Done with OAuth dance with Github for %s (%s)." | ||
% (user_info['login'], user_info['id'])) | ||
|
||
return user_info | ||
|
||
|
||
def resolve(screen_name): | ||
"""Given str, return a participant_id. | ||
""" | ||
FETCH = """\ | ||
SELECT participant_id | ||
FROM social_network_users | ||
WHERE network='twitter' | ||
AND user_info -> 'screen_namec' = %s | ||
""" # XXX Uniqueness constraint on screen_name? | ||
rec = db.fetchone(FETCH, (screen_name,)) | ||
if rec is None: | ||
raise Exception("Twitter user %s has no participant." % (screen_name)) | ||
return rec['participant_id'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
"""Twitter user page on Gittip. | ||
""" | ||
import decimal | ||
|
||
import requests | ||
from aspen import json, Response | ||
from gittip import AMOUNTS, CARDINALS, db, get_tip, get_number_of_backers | ||
from gittip.networks import twitter | ||
|
||
|
||
# ========================================================================== ^L | ||
|
||
# Try to load from Twitter. | ||
# ========================= | ||
|
||
url = "https://api.twitter.com/1/users/show.json?screen_name=%s" | ||
userinfo = requests.get(url % path['screen_name']) | ||
if userinfo.status_code != 200: | ||
raise Response(404) | ||
userinfo = json.loads(userinfo.text) | ||
|
||
|
||
# Try to load from Gittip. | ||
# ======================== | ||
|
||
participant = False | ||
username = userinfo['screen_name'] | ||
name = userinfo.get('name') | ||
if not name: | ||
name = username | ||
userinfo['html_url'] = "https://twitter.com/%s" % username | ||
|
||
participant_id, is_claimed, is_locked, balance = twitter.upsert(userinfo) | ||
can_tip = not is_locked | ||
lock_action = "unlock" if is_locked else "lock" | ||
if is_claimed: | ||
request.redirect('/%s/' % participant_id) | ||
|
||
if not user.ANON: | ||
my_tip = get_tip(user.id, participant_id) | ||
|
||
tip_or_pledge = "pledge" | ||
nbackers = get_number_of_backers(participant_id) | ||
|
||
# ========================================================================== ^L | ||
{% extends templates/participant.html %} | ||
|
||
{% block their_voice %} | ||
{% if is_locked %} | ||
|
||
<h2 class="first"><b>{{ username }}</b> has opted out of Gittip.</h2> | ||
|
||
<p>If you are <a href="{{ userinfo.get('html_url', '') }}">{{ username }}</a> | ||
on Twitter, you can unlock your account to allow people to | ||
pledge tips to you on Gittip. We never collect any money on your behalf | ||
until you explicitly opt in.</p> | ||
|
||
<a href="{{ twitter.oauth_url(website, u'unlock', username) }}" | ||
><button>Unlock</button></a> | ||
|
||
{% else %} | ||
<script> | ||
$(document).ready(Gittip.initTipButtons); | ||
</script> | ||
|
||
<h2 class="first"><b>{{ name }}</b> has not joined Gittip.</h2> | ||
|
||
{% if user.ANON %} | ||
<ul id="accounts"> | ||
<li> | ||
<img src="{{ userinfo.get('avatar_url', '/assets/%s/no-avatar.png' % __version__) }}" /> | ||
Are you <a href="{{ userinfo['html_url'] }}">{{ userinfo['screen_name'] }}</a> from Twitter?<br /> | ||
<a href="{{ twitter.oauth_url(website, u'opt-in', username) }}">Click here</a> to opt in to Gittip. | ||
</li> | ||
</ul> | ||
{% else %} | ||
<ul id="accounts"> | ||
<li> | ||
<img src="{{ userinfo.get('avatar_url', '/assets/%s/no-avatar.png' % __version__) }}" /> | ||
Are you <a href="{{ userinfo['html_url'] }}">{{ userinfo['screen_name'] }}</a> from Twitter?<br /> | ||
You’ll have to <a href="/sign-out.html">sign out</a> and sign back in to claim this account. | ||
</li> | ||
</ul> | ||
{% end %} | ||
|
||
|
||
{% if nbackers == 0 %} | ||
{% elif nbackers == 1 %} | ||
<h3>There is one person ready to give.</h3> | ||
{% elif nbackers < 10 %} | ||
<h3>There are {{ CARDINALS[nbackers] }} people ready to give.</h3> | ||
{% else %} | ||
<h3>There are {{ nbackers }} people ready to give.</h3> | ||
{% end %} | ||
|
||
|
||
{% if not user.ANON %} | ||
|
||
<p>{{ 'But we' if nbackers > 0 else 'We' }} will never collect money on | ||
behalf of {{ username }} until they ask us to.</p> | ||
|
||
{% else %} | ||
|
||
<p>{{ 'But we' if nbackers > 0 else 'We' }} will never collect money on | ||
your behalf until you ask us to.</p> | ||
|
||
<h3>Don’t like what you see?</h3> | ||
|
||
<p>If you are {{ username }} you can explicitly opt out of Gittip by | ||
locking this account. We don’t allow new pledges to locked | ||
accounts.</p> | ||
|
||
<a href="{{ twitter.oauth_url(website, u'lock', username) }}" | ||
><button>Lock</button></a> | ||
|
||
{% end %} | ||
{% end %} | ||
{% end %} |