Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
Move claim/id routines to Participant (#406)
Browse files Browse the repository at this point in the history
  • Loading branch information
chadwhitacre committed Dec 7, 2012
1 parent 449f307 commit 9b2d176
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 59 deletions.
2 changes: 2 additions & 0 deletions configure-aspen.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
gittip.wireup.canonical()
gittip.wireup.db()
gittip.wireup.billing()
gittip.wireup.id_restrictions(website)


website.github_client_id = os.environ['GITHUB_CLIENT_ID'].decode('ASCII')
website.github_client_secret = os.environ['GITHUB_CLIENT_SECRET'].decode('ASCII')
Expand Down
1 change: 1 addition & 0 deletions gittip/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def age():
OLD_AMOUNTS= [Decimal(a) for a in ('0.25',)]

AMOUNTS = [Decimal(a) for a in ('0.00', '1.00', '3.00', '6.00', '12.00', '24.00')]
RESTRICTED_IDS = None


# canonizer
Expand Down
48 changes: 1 addition & 47 deletions gittip/elsewhere/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os
import random

from aspen import log, Response
from aspen import log
from aspen.utils import typecheck
from gittip import db
from psycopg2 import IntegrityError
Expand All @@ -11,39 +10,6 @@ class RunawayTrain(Exception):
pass


ALLOWED_ASCII = set("0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
".,-_;:@ ")

def change_participant_id(website, old, suggested):
"""Raise response return None.
We want to be pretty loose with usernames. Unicode is allowed. So are
spaces. Control characters aren't. We also limit to 32 characters in
length.
"""
for i, c in enumerate(suggested):
if i == 32:
raise Response(413) # Request Entity Too Large (more or less)
elif ord(c) < 128 and c not in ALLOWED_ASCII:
raise Response(400) # Yeah, no.
elif c not in ALLOWED_ASCII:
raise Response(400) # XXX Burned by an Aspen bug. :`-(
# https://github.com/whit537/aspen/issues/102

if website is not None and suggested in os.listdir(website.www_root):
raise Response(400)

if suggested != old:
rec = db.fetchone( "UPDATE participants SET id=%s WHERE id=%s " \
"RETURNING id", (suggested, old))
# May raise IntegrityError
assert rec is not None # sanity check
assert suggested == rec['id'] # sanity check


def get_a_participant_id():
"""Return a random participant_id.
Expand Down Expand Up @@ -214,15 +180,3 @@ def upsert(platform, user_id, username, user_info):
, is_locked
, rec['balance']
)


def set_as_claimed(participant_id):
CLAIMED = """\
UPDATE participants
SET claimed_time=CURRENT_TIMESTAMP
WHERE id=%s
AND claimed_time IS NULL
"""
db.execute(CLAIMED, (participant_id,))
57 changes: 57 additions & 0 deletions gittip/participant.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
"""Defines a Participant class.
"""
from aspen import Response
from decimal import Decimal

import gittip
from aspen.utils import typecheck


ASCII_ALLOWED_IN_PARTICIPANT_ID = set("0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
".,-_;:@ ")


class NoParticipantId(StandardError):
"""Represent a bug where we treat an anonymous user as a participant.
"""
Expand Down Expand Up @@ -43,6 +50,11 @@ def get_details(self):
return gittip.db.fetchone(SELECT, (self.id,))


# Claiming
# ========
# An unclaimed Participant is a stub that's created when someone pledges to
# give to an AccountElsewhere that's not been connected on Gittip yet.

@require_id
def resolve_unclaimed(self):
"""Given a participant_id, return an URL path.
Expand All @@ -58,6 +70,51 @@ def resolve_unclaimed(self):
out = '/on/twitter/%s/' % rec['user_info']['screen_name']
return out

@require_id
def set_as_claimed(self):
CLAIM = """\
UPDATE participants
SET claimed_time=CURRENT_TIMESTAMP
WHERE id=%s
AND claimed_time IS NULL
"""
gittip.db.execute(CLAIM, (self.id,))



@require_id
def change_id(self, suggested):
"""Raise Response or return None.
We want to be pretty loose with usernames. Unicode is allowed--XXX
aspen bug :(. So are spaces.Control characters aren't. We also limit to
32 characters in length.
"""
for i, c in enumerate(suggested):
if i == 32:
raise Response(413) # Request Entity Too Large (more or less)
elif ord(c) < 128 and c not in ASCII_ALLOWED_IN_PARTICIPANT_ID:
raise Response(400) # Yeah, no.
elif c not in ASCII_ALLOWED_IN_PARTICIPANT_ID:
raise Response(400) # XXX Burned by an Aspen bug. :`-(
# https://github.com/whit537/aspen/issues/102

if suggested in gittip.RESTRICTED_IDS:
raise Response(400)

if suggested != self.id:
# Will raise IntegrityError if the desired participant_id is taken.
rec = gittip.db.fetchone("UPDATE participants "
"SET id=%s WHERE id=%s "
"RETURNING id", (suggested, self.id))

assert rec is not None # sanity check
assert suggested == rec['id'] # sanity check
self.id = suggested


@require_id
def get_accounts_elsewhere(self):
Expand Down
5 changes: 3 additions & 2 deletions gittip/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ def create_schema(db):
]

def populate_db_with_dummy_data(db):
from gittip.elsewhere import github, change_participant_id
from gittip.elsewhere import github
from gittip.participant import Participant
for user_id, login in GITHUB_USERS:
participant_id, a,b,c = github.upsert({"id": user_id, "login": login})
change_participant_id(None, participant_id, login)
Participant(participant_id).change_id(login)


class GittipBaseDBTest(unittest.TestCase):
Expand Down
4 changes: 4 additions & 0 deletions gittip/wireup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ def billing():
stripe.api_key= os.environ['STRIPE_SECRET_API_KEY']
stripe.publishable_api_key= os.environ['STRIPE_PUBLISHABLE_API_KEY']
balanced.configure(os.environ['BALANCED_API_SECRET'])


def id_restrictions(website):
gittip.RESTRICTED_IDS = os.listdir(website.www_root)
3 changes: 1 addition & 2 deletions www/%participant_id/participant_id.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from aspen import Response
from gittip.elsewhere import change_participant_id
from psycopg2 import IntegrityError

# ========================================================================== ^L
Expand All @@ -10,7 +9,7 @@ if user.ANON:
new_participant_id = request.body['participant_id']

try:
change_participant_id(website, user.id, new_participant_id)
user.change_id(new_participant_id)
response.body = {"participant_id": new_participant_id}
except IntegrityError:
raise Response(409) # Conflict
8 changes: 4 additions & 4 deletions www/on/github/associate
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ the Gittip community.
"""
from aspen import log, Response
from gittip import db
from gittip.elsewhere import change_participant_id, github, set_as_claimed
from gittip.authentication import User
from gittip.elsewhere import github
from psycopg2 import IntegrityError

# ========================== ^L
Expand All @@ -34,14 +34,14 @@ if login is None:
log(u"%s wants to %s" % (login, action))
if action == 'opt-in': # opt in
participant_id, is_claimed, is_locked, balance = github.upsert(user_info)
user = User.from_id(participant_id) # give them a session
if not is_claimed:
user.set_as_claimed()
try:
change_participant_id(website, participant_id, login)
user.change_id(login)
participant_id = login
except (Response, IntegrityError):
pass
set_as_claimed(participant_id)
user = User.from_id(participant_id) # give them a session
else: # lock or unlock
if then != login:

Expand Down
8 changes: 4 additions & 4 deletions www/on/twitter/associate
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import requests
from oauth_hook import OAuthHook
from aspen import log, Response, json
from gittip import db
from gittip.elsewhere import change_participant_id, twitter, set_as_claimed
from gittip.authentication import User
from gittip.elsewhere import twitter
from urlparse import parse_qs
from psycopg2 import IntegrityError

Expand Down Expand Up @@ -63,14 +63,14 @@ user_info['html_url'] = "https://twitter.com/" + screen_name
log(u"%s wants to %s" % (screen_name, action))
if action == 'opt-in': # opt in
participant_id, is_claimed, is_locked, balance = twitter.upsert(user_info)
user = User.from_id(participant_id) # give them a session
if not is_claimed:
user.set_as_claimed()
try:
change_participant_id(website, participant_id, screen_name)
user.change_id(screen_name)
participant_id = screen_name
except (Response, IntegrityError):
pass
set_as_claimed(participant_id)
user = User.from_id(participant_id) # give them a session
else: # lock or unlock
if then != screen_name:

Expand Down

0 comments on commit 9b2d176

Please sign in to comment.