Fix some paypal troubles
This commit is contained in:
Родитель
960b835ac8
Коммит
0f8b684b3c
|
@ -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']
|
||||
|
|
Загрузка…
Ссылка в новой задаче