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

Commit

Permalink
Factor set_paypal_address out of endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
chadwhitacre committed Apr 27, 2017
1 parent ed9ca00 commit 56c616c
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 12 deletions.
8 changes: 4 additions & 4 deletions gratipay/models/participant/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,21 +338,21 @@ def get_email(self, address, cursor=None, and_lock=False):
return (cursor or self.db).one(sql, (self.id, address))


def get_emails(self):
def get_emails(self, cursor=None):
"""Return a list of all email addresses on file for this participant.
"""
return self.db.all("""
return (cursor or self.db).all("""
SELECT *
FROM emails
WHERE participant_id=%s
ORDER BY id
""", (self.id,))


def get_verified_email_addresses(self):
def get_verified_email_addresses(self, cursor=None):
"""Return a list of verified email addresses on file for this participant.
"""
return [email.address for email in self.get_emails() if email.verified]
return [email.address for email in self.get_emails(cursor) if email.verified]


def remove_email(self, address):
Expand Down
21 changes: 21 additions & 0 deletions gratipay/models/participant/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import absolute_import, division, print_function, unicode_literals

import braintree
from psycopg2 import IntegrityError, errorcodes

from ..exchange_route import ExchangeRoute
from ...billing.instruments import CreditCard
Expand All @@ -12,22 +13,26 @@ class Routes(object):
"""Participants have payment routes to get money into and out of Gratipay.
"""


def get_paypal_error(self):
"""Return the error associated with the participant's PayPal account, or ``None``.
"""
return getattr(ExchangeRoute.from_network(self, 'paypal'), 'error', None)


def get_credit_card_error(self):
"""Return the error associated with the participant's credit card, or ``None``.
"""
return getattr(ExchangeRoute.from_network(self, 'braintree-cc'), 'error', None)


@property
def has_payout_route(self):
"""A boolean computed property, whether the participant has a known-working payout route.
"""
return bool(self.get_payout_routes(good_only=True))


def get_payout_routes(self, good_only=False, cursor=None):
"""Return a list of payout routes. If ``good_only`` evaluates to rue then only
known-working payout routes are included.
Expand All @@ -42,6 +47,7 @@ def get_payout_routes(self, good_only=False, cursor=None):
out.append(route)
return out


def get_braintree_account(self):
"""Fetch or create a braintree account for this participant.
"""
Expand All @@ -64,6 +70,7 @@ def get_braintree_account(self):
customer = braintree.Customer.find(self.braintree_customer_id)
return customer


def get_braintree_token(self):
"""Return the braintree token for this participant.
"""
Expand All @@ -72,6 +79,7 @@ def get_braintree_token(self):
token = braintree.ClientToken.generate({'customer_id': account.id})
return token


def credit_card_expiring(self):
"""Return a boolean, whether the participant's credit card is set to expire soon.
"""
Expand All @@ -83,3 +91,16 @@ def credit_card_expiring(self):
if not (year and month):
return False
return is_card_expiring(int(year), int(month))


def set_paypal_address(self, address, cursor=None):
"""Given an email address as a string, set it as the participant's PayPal address.
"""
assert address in self.get_verified_email_addresses(cursor)
try:
ExchangeRoute.insert(self, 'paypal', address, cursor=cursor)
except IntegrityError as e:
if e.pgcode != errorcodes.UNIQUE_VIOLATION:
raise
existing_route = ExchangeRoute.from_address(self, 'paypal', address)
existing_route.revive()
19 changes: 19 additions & 0 deletions tests/py/test_participant_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,22 @@ def test_scopes_to_cursor(self):
assert alice.get_payout_routes() == []
assert alice.get_payout_routes(cursor=cursor) == [route]
assert alice.get_payout_routes() == [route]


class SetPayPalAddress(Harness):

def test_sets_paypal_address(self):
alice = self.make_participant('alice', claimed_time='now')
self.add_and_verify_email(alice, '[email protected]')
alice.set_paypal_address('[email protected]')
paypal = alice.get_payout_routes()[0]
assert paypal.network == 'paypal'
assert paypal.address == '[email protected]'

def test_scopes_to_cursor(self):
alice = self.make_participant('alice', claimed_time='now')
self.add_and_verify_email(alice, '[email protected]')
with self.db.get_cursor() as cursor:
alice.set_paypal_address('[email protected]', cursor)
assert alice.get_payout_routes() == []
assert alice.get_payout_routes(cursor=cursor)[0].address == '[email protected]'
9 changes: 1 addition & 8 deletions www/~/%username/routes/associate.json.spt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import braintree
from gratipay.billing.exchanges import repr_exception
from gratipay.models.exchange_route import ExchangeRoute
from gratipay.utils import bitcoin, get_participant
from psycopg2 import IntegrityError, errorcodes

[---]

Expand Down Expand Up @@ -40,13 +39,7 @@ if change:
elif network == 'paypal':
if address not in participant.get_verified_email_addresses():
raise Response(400, _("Only verified email addresses allowed."))
try:
ExchangeRoute.insert(participant, network, address)
except IntegrityError as e:
if e.pgcode != errorcodes.UNIQUE_VIOLATION:
raise
existing_route = ExchangeRoute.from_address(participant, network, address)
existing_route.revive()
participant.set_paypal_address(address)

elif network == 'bitcoin':
if not bitcoin.validate(address):
Expand Down

0 comments on commit 56c616c

Please sign in to comment.