This commit is contained in:
Wil Clouser 2010-05-01 23:46:17 -07:00
Родитель 960b835ac8
Коммит 0f8b684b3c
2 изменённых файлов: 59 добавлений и 13 удалений

Просмотреть файл

@ -1,9 +1,12 @@
import urllib
from django import http, test
from django.conf import settings
from django.core.cache import cache, parse_backend_uri
from amo.urlresolvers import reverse
from mock import patch, Mock
from nose import SkipTest
from nose.tools import eq_
import test_utils
@ -73,7 +76,6 @@ class TestStuff(test_utils.TestCase):
response = self.client.get("/%s/firefox/?%slang=%s&next=/" % (
locale, xeno, locale), follow=True)
doc = PyQuery(response.content)
box = PyQuery(response.content)('#locale-only').attr('checked')
cookie = self.client.cookies.get("locale-only")
@ -109,6 +111,7 @@ class TestPaypal(test_utils.TestCase):
def setUp(self):
self.url = reverse('amo.paypal')
self.item = 1234567890
def urlopener(self, status):
m = Mock()
@ -136,4 +139,28 @@ class TestPaypal(test_utils.TestCase):
def test_get_not_allowed(self):
response = self.client.get(self.url)
eq_(response.status_code, 405)
assert isinstance(response, http.HttpResponseNotAllowed)
@patch('amo.views.urllib2.urlopen')
def test_mysterious_contribution(self, urlopen):
scheme, servers, _ = parse_backend_uri(settings.CACHE_BACKEND)
if 'dummy' in scheme:
raise SkipTest()
urlopen.return_value = self.urlopener('VERIFIED')
key = "%s%s:%s" % (settings.CACHE_PREFIX, 'contrib', self.item)
data = {'txn_id': 100,
'payer_email': 'jbalogh@wherever.com',
'receiver_email': 'clouserw@gmail.com',
'mc_gross': '99.99',
'item_number': self.item,
'payment_status': 'Completed'}
response = self.client.post(self.url, data)
assert isinstance(response, http.HttpResponseServerError)
eq_(cache.get(key), 1)
cache.set(key, 10, 1209600)
response = self.client.post(self.url, data)
assert isinstance(response, http.HttpResponse)
eq_(cache.get(key), None)

Просмотреть файл

@ -3,7 +3,7 @@ import urllib2
from django import http
from django.conf import settings
from django.core.cache import parse_backend_uri
from django.core.cache import cache, parse_backend_uri
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
@ -68,6 +68,10 @@ def paypal(request):
IPN will retry periodically until it gets success (status=200). Any
db errors or replication lag will result in an exception and http
status of 500, which is good so PayPal will try again later.
PayPal IPN variables available at:
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content
&content_ID=developer/e_howto_html_IPNandPDTVariables
"""
if request.method != 'POST':
return http.HttpResponseNotAllowed(['POST'])
@ -75,31 +79,46 @@ def paypal(request):
# Check that the request is valid and coming from PayPal.
data = request.POST.copy()
data['cmd'] = '_notify-validate'
if urllib2.urlopen(settings.PAYPAL_CGI_URL,
data.urlencode(), 20).readline() != 'VERIFIED':
pr = urllib2.urlopen(settings.PAYPAL_CGI_URL,
data.urlencode(), 20).readline()
if pr != 'VERIFIED':
log.error("Expecting 'VERIFIED' from PayPal, got '%s'. Failing." % pr)
return http.HttpResponseForbidden('Invalid confirmation')
if request.POST.get('txn_type', '').startswith('subscr_'):
SubscriptionEvent.objects.create(post_data=php.serialize(request.POST))
return http.HttpResponse()
return http.HttpResponse('Success!')
# We only care about completed transactions.
if request.POST.get('payment_status') != 'Completed':
return http.HttpResponse('Payment not completed')
# Make sure transaction has not yet been processed.
if len(Contribution.objects.filter(transaction_id=request.POST['txn_id'])) > 0:
if (Contribution.objects
.filter(transaction_id=request.POST['txn_id']).count()) > 0:
return http.HttpResponse('Transaction already processed')
# Fetch and update the contribution - item_number is the uuid we created.
try:
c = Contribution.objects.get(uuid=request.POST['item_number'])
c = Contribution.objects.no_cache().get(
uuid=request.POST['item_number'])
except Contribution.DoesNotExist:
# If these warnings frequently occur on the first IPN attempt,
# perhaps consider logging only if POST['resend'] is set.
ipn_type = 'repeated' if 'resend' in request.POST else 'initial'
log.warning('Contribution (uuid=%s) not found for %s IPN request.'
% (request.POST['item_number'], ipn_type))
key = "%s%s:%s" % (settings.CACHE_PREFIX, 'contrib',
request.POST['item_number'])
count = cache.get(key, 0) + 1
log.warning('Contribution (uuid=%s) not found for IPN request #%s.'
% (request.POST['item_number'], count))
if count > 10:
logme = (request.POST['txn_id'], request.POST['payer_email'],
request.POST['receiver_email'], request.POST['mc_gross'])
log.error("Paypal sent a transaction that we don't know about and "
"we're giving up on it! (TxnID={d[txn_id]}; "
"From={d[payer_email]}; To={d[receiver_email]}; "
"Amount={d[mc_gross]})".format(d=request.POST))
cache.delete(key)
return http.HttpResponse('Transaction not found; skipping.')
cache.set(key, count, 1209600) # This is 2 weeks.
return http.HttpResponseServerError('Contribution not found')
c.transaction_id = request.POST['txn_id']