add in the feature flag (bug 627077 and 635351)
This commit is contained in:
Родитель
e01ca949df
Коммит
71c2ce878e
|
@ -1,3 +1,5 @@
|
|||
from django.conf import settings
|
||||
|
||||
import jinja2
|
||||
|
||||
from jingo import register, env
|
||||
|
@ -44,7 +46,8 @@ def flag(context, addon):
|
|||
@register.function
|
||||
def support_addon(addon):
|
||||
t = env.get_template('addons/support_addon.html')
|
||||
return jinja2.Markup(t.render(addon=addon, amo=amo))
|
||||
return jinja2.Markup(t.render(addon=addon, amo=amo,
|
||||
use_embedded=settings.PAYPAL_USE_EMBEDDED))
|
||||
|
||||
|
||||
@register.inclusion_tag('addons/performance_note.html')
|
||||
|
|
|
@ -119,6 +119,17 @@
|
|||
'$', '<input type="text" name="onetime-amount" value=""/>')|safe }}
|
||||
</label>
|
||||
</li>
|
||||
{% if not settings.PAYPAL_USE_EMBEDDED %}
|
||||
<li>
|
||||
<input type="radio" name="type" value="monthly"
|
||||
id="contrib-monthly"/>
|
||||
<label for="contrib-monthly">
|
||||
{# L10n: {0} is a currency symbol (e.g., $),
|
||||
{1} is an amount input field #}
|
||||
{{ _('A regular monthly contribution of {0} {1}')|f(
|
||||
'$', '</label><input type="text" name="monthly-amount" value=""/>')|safe }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<h4 class="comment">
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
{% else %}
|
||||
<h4>{{ _('Payment completed') }}</h4>
|
||||
{% endif %}
|
||||
<p><a href="{{ url('addons.detail', addon.slug) }}">{{ _('Return to the addon.') }}</a></p>
|
||||
<p><a id="paypal-result" href="{{ url('addons.detail', addon.slug) }}">{{ _('Return to the addon.') }}</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -21,7 +21,11 @@
|
|||
{% endtrans %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if use_embedded %}
|
||||
<a href="{{ url('addons.detail', addon.slug) }}#contribute-confirm" class="no-suggested-amount">{{ _('Support this add-on') }}</a>
|
||||
{% else %}
|
||||
<a href="{{ base }}">{{ _('Support this add-on') }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime, timedelta
|
||||
from email import utils
|
||||
from decimal import Decimal
|
||||
import re
|
||||
from email import utils
|
||||
import json
|
||||
import re
|
||||
import urlparse
|
||||
|
||||
from django import test
|
||||
from django.conf import settings
|
||||
|
@ -143,10 +144,11 @@ class TestContributeInstalled(test_utils.TestCase):
|
|||
eq_(title[:37], 'Thank you for installing Gmail S/MIME')
|
||||
|
||||
|
||||
class TestContribute(test_utils.TestCase):
|
||||
class TestContributeEmbedded(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_592']
|
||||
|
||||
def setUp(self):
|
||||
settings.PAYPAL_USE_EMBEDDED = True
|
||||
self.addon = Addon.objects.get(pk=592)
|
||||
self.detail_url = reverse('addons.detail', args=[self.addon.slug])
|
||||
|
||||
|
@ -238,6 +240,150 @@ class TestContribute(test_utils.TestCase):
|
|||
assert not json.loads(res.content)['paykey']
|
||||
|
||||
|
||||
class TestContribute(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_592']
|
||||
|
||||
def setUp(self):
|
||||
settings.PAYPAL_USE_EMBEDDED = False
|
||||
|
||||
def test_invalid_is_404(self):
|
||||
"""we get a 404 in case of invalid addon id"""
|
||||
response = self.client.get(reverse('addons.contribute', args=[1]))
|
||||
eq_(response.status_code, 404)
|
||||
|
||||
def test_redirect_params_no_type(self):
|
||||
"""Test that we have the required ppal params when no type is given"""
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']), follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
required_params = ['bn', 'business', 'charset', 'cmd', 'item_name',
|
||||
'no_shipping', 'notify_url',
|
||||
'return', 'item_number']
|
||||
for param in required_params:
|
||||
assert(redirect_url.find(param + '=') > -1), \
|
||||
"param [%s] not found" % param
|
||||
|
||||
def test_redirect_params_common(self):
|
||||
"""Test for the common values that do not change based on type,
|
||||
Check that they have expected values"""
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']), follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
assert(re.search('business=([^&]+)', redirect_url))
|
||||
common_params = {'bn': r'-AddonID592',
|
||||
'business': r'gmailsmime%40seantek.com',
|
||||
'charset': r'utf-8',
|
||||
'cmd': r'_donations',
|
||||
'item_name': r'Contribution\+for\+Gmail\+S%2FMIME',
|
||||
'no_shipping': r'1',
|
||||
'notify_url': r'%2Fservices%2Fpaypal',
|
||||
'return': r'x',
|
||||
'item_number': r'[a-f\d]{32}'}
|
||||
|
||||
message = 'param [%s] unexpected value: given [%s], ' \
|
||||
+ 'expected pattern [%s]'
|
||||
for param, value_pattern in common_params.items():
|
||||
match = re.search(r'%s=([^&]+)' % param, redirect_url)
|
||||
assert(match and re.search(value_pattern, match.group(1))), \
|
||||
message % (param, match.group(1), value_pattern)
|
||||
|
||||
def test_redirect_params_type_suggested(self):
|
||||
"""Test that we have the required ppal param when type
|
||||
suggested is given"""
|
||||
request_params = '?type=suggested'
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']) + request_params,
|
||||
follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
required_params = ['amount', 'bn', 'business', 'charset',
|
||||
'cmd', 'item_name', 'no_shipping', 'notify_url',
|
||||
'return', 'item_number']
|
||||
for param in required_params:
|
||||
assert(redirect_url.find(param + '=') > -1), \
|
||||
"param [%s] not found" % param
|
||||
|
||||
def test_redirect_params_type_onetime(self):
|
||||
"""Test that we have the required ppal param when
|
||||
type onetime is given"""
|
||||
request_params = '?type=onetime&onetime-amount=42'
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']) + request_params,
|
||||
follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
required_params = ['amount', 'bn', 'business', 'charset', 'cmd',
|
||||
'item_name', 'no_shipping', 'notify_url',
|
||||
'return', 'item_number']
|
||||
for param in required_params:
|
||||
assert(redirect_url.find(param + '=') > -1), \
|
||||
"param [%s] not found" % param
|
||||
|
||||
assert(redirect_url.find('amount=42') > -1)
|
||||
|
||||
def test_ppal_return_url_not_relative(self):
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']), follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
|
||||
assert(re.search('\?|&return=https?%3A%2F%2F', redirect_url)), \
|
||||
("return URL param did not start w/ "
|
||||
"http%3A%2F%2F (http://) [%s]" % redirect_url)
|
||||
|
||||
def test_redirect_params_type_monthly(self):
|
||||
"""Test that we have the required ppal param when
|
||||
type monthly is given"""
|
||||
request_params = '?type=monthly&monthly-amount=42'
|
||||
response = self.client.get(reverse('addons.contribute',
|
||||
args=['a592']) + request_params,
|
||||
follow=True)
|
||||
redirect_url = response.redirect_chain[0][0]
|
||||
required_params = ['no_note', 'a3', 't3', 'p3', 'bn', 'business',
|
||||
'charset', 'cmd', 'item_name', 'no_shipping',
|
||||
'notify_url', 'return', 'item_number']
|
||||
for param in required_params:
|
||||
assert(redirect_url.find(param + '=') > -1), \
|
||||
"param [%s] not found" % param
|
||||
|
||||
assert(redirect_url.find('cmd=_xclick-subscriptions') > -1), \
|
||||
'param a3 was not 42'
|
||||
assert(redirect_url.find('p3=12') > -1), 'param p3 was not 12'
|
||||
assert(redirect_url.find('t3=M') > -1), 'param t3 was not M'
|
||||
assert(redirect_url.find('a3=42') > -1), 'param a3 was not 42'
|
||||
assert(redirect_url.find('no_note=1') > -1), 'param no_note was not 1'
|
||||
|
||||
def test_paypal_bounce(self):
|
||||
"""Paypal is retarded and posts to this page."""
|
||||
args = dict(args=['a3615'])
|
||||
r = self.client.post(reverse('addons.thanks', **args))
|
||||
self.assertRedirects(r, reverse('addons.detail', **args))
|
||||
|
||||
def test_unicode_comment(self):
|
||||
r = self.client.get(reverse('addons.contribute', args=['a592']),
|
||||
{'comment': u'版本历史记录'})
|
||||
eq_(r.status_code, 302)
|
||||
assert r['Location'].startswith(settings.PAYPAL_CGI_URL)
|
||||
|
||||
def test_organization(self):
|
||||
c = Charity.objects.create(name='moz', url='moz.com', paypal='mozcom')
|
||||
addon = Addon.objects.get(id=592)
|
||||
addon.update(charity=c)
|
||||
|
||||
r = self.client.get(reverse('addons.contribute', args=['a592']))
|
||||
eq_(r.status_code, 302)
|
||||
qs = dict(urlparse.parse_qsl(r['Location']))
|
||||
eq_(qs['item_name'], 'Contribution for moz')
|
||||
eq_(qs['business'], 'mozcom')
|
||||
|
||||
contrib = Contribution.objects.get(addon=addon)
|
||||
eq_(addon.charity_id, contrib.charity_id)
|
||||
|
||||
def test_no_org(self):
|
||||
addon = Addon.objects.get(id=592)
|
||||
r = self.client.get(reverse('addons.contribute', args=['a592']))
|
||||
eq_(r.status_code, 302)
|
||||
contrib = Contribution.objects.get(addon=addon)
|
||||
eq_(contrib.charity_id, None)
|
||||
|
||||
|
||||
class TestDeveloperPages(test_utils.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_592',
|
||||
'base/users', 'addons/eula+contrib-addon',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf.urls.defaults import patterns, url, include
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.shortcuts import redirect
|
||||
|
||||
from . import views
|
||||
|
@ -20,9 +21,14 @@ detail_patterns = patterns('',
|
|||
{'page': 'roadblock'}, name='addons.roadblock'),
|
||||
url('^contribute/installed/', views.developers,
|
||||
{'page': 'installed'}, name='addons.installed'),
|
||||
url('^contribute/thanks',
|
||||
csrf_exempt(lambda r, addon_id: redirect('addons.detail', addon_id)),
|
||||
name='addons.thanks'),
|
||||
url('^contribute/$', views.contribute, name='addons.contribute'),
|
||||
url('^contribute/(?P<status>cancel|complete)$',
|
||||
views.paypal_result, name='addons.paypal'),
|
||||
url('^contribute/(?P<status>cancel|complete)$', views.paypal_result,
|
||||
name='addons.paypal'),
|
||||
|
||||
|
||||
('^about$', lambda r, addon_id: redirect('addons.installed',
|
||||
addon_id, permanent=True)),
|
||||
|
||||
|
|
|
@ -412,8 +412,55 @@ def developers(request, addon, page):
|
|||
'page': page, 'version': version})
|
||||
|
||||
|
||||
@addon_view
|
||||
def contribute(request, addon):
|
||||
def old_contribute(request, addon):
|
||||
contrib_type = request.GET.get('type', '')
|
||||
is_suggested = contrib_type == 'suggested'
|
||||
source = request.GET.get('source', '')
|
||||
comment = request.GET.get('comment', '')
|
||||
|
||||
amount = {
|
||||
'suggested': addon.suggested_amount,
|
||||
'onetime': request.GET.get('onetime-amount', ''),
|
||||
'monthly': request.GET.get('monthly-amount', '')}.get(contrib_type, '')
|
||||
|
||||
contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest()
|
||||
|
||||
contrib = Contribution(addon_id=addon.id,
|
||||
charity_id=addon.charity_id,
|
||||
amount=amount,
|
||||
source=source,
|
||||
source_locale=request.LANG,
|
||||
annoying=addon.annoying,
|
||||
uuid=str(contribution_uuid),
|
||||
is_suggested=is_suggested,
|
||||
suggested_amount=addon.suggested_amount,
|
||||
comment=comment)
|
||||
contrib.save()
|
||||
|
||||
return_url = "%s?%s" % (reverse('addons.thanks', args=[addon.slug]),
|
||||
urllib.urlencode({'uuid': contribution_uuid}))
|
||||
# L10n: {0} is an add-on name.
|
||||
if addon.charity:
|
||||
name, paypal = addon.charity.name, addon.charity.paypal
|
||||
else:
|
||||
name, paypal = addon.name, addon.paypal_id
|
||||
contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name))
|
||||
redirect_url_params = contribute_url_params(
|
||||
paypal,
|
||||
addon.id,
|
||||
contrib_for,
|
||||
absolutify(return_url),
|
||||
amount,
|
||||
contribution_uuid,
|
||||
contrib_type == 'monthly',
|
||||
comment)
|
||||
|
||||
return http.HttpResponseRedirect(settings.PAYPAL_CGI_URL
|
||||
+ '?'
|
||||
+ urllib.urlencode(redirect_url_params))
|
||||
|
||||
|
||||
def embedded_contribute(request, addon):
|
||||
contrib_type = request.GET.get('type', 'suggested')
|
||||
is_suggested = contrib_type == 'suggested'
|
||||
source = request.GET.get('source', '')
|
||||
|
@ -479,6 +526,56 @@ def contribute(request, addon):
|
|||
return http.HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@addon_view
|
||||
def contribute(request, addon):
|
||||
if settings.PAYPAL_USE_EMBEDDED:
|
||||
return embedded_contribute(request, addon)
|
||||
else:
|
||||
return old_contribute(request, addon)
|
||||
|
||||
|
||||
def contribute_url_params(business, addon_id, item_name, return_url,
|
||||
amount='', item_number='',
|
||||
monthly=False, comment=''):
|
||||
|
||||
lang = translation.get_language()
|
||||
try:
|
||||
paypal_lang = settings.PAYPAL_COUNTRYMAP[lang]
|
||||
except KeyError:
|
||||
lang = lang.split('-')[0]
|
||||
paypal_lang = settings.PAYPAL_COUNTRYMAP.get(lang, 'US')
|
||||
|
||||
# Get all the data elements that will be URL params
|
||||
# on the Paypal redirect URL.
|
||||
data = {'business': business,
|
||||
'item_name': item_name,
|
||||
'item_number': item_number,
|
||||
'bn': settings.PAYPAL_BN + '-AddonID' + str(addon_id),
|
||||
'no_shipping': '1',
|
||||
'return': return_url,
|
||||
'charset': 'utf-8',
|
||||
'lc': paypal_lang,
|
||||
'notify_url': "%s%s" % (settings.SERVICES_URL,
|
||||
reverse('amo.paypal'))}
|
||||
|
||||
if not monthly:
|
||||
data['cmd'] = '_donations'
|
||||
if amount:
|
||||
data['amount'] = amount
|
||||
else:
|
||||
data.update({
|
||||
'cmd': '_xclick-subscriptions',
|
||||
'p3': '12', # duration: for 12 months
|
||||
't3': 'M', # time unit, 'M' for month
|
||||
'a3': amount, # recurring contribution amount
|
||||
'no_note': '1'}) # required: no "note" text field for user
|
||||
|
||||
if comment:
|
||||
data['custom'] = comment
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@addon_view
|
||||
def paypal_result(request, addon, status):
|
||||
uuid = request.GET.get('uuid')
|
||||
|
|
|
@ -136,6 +136,7 @@ class TestPaypal(test_utils.TestCase):
|
|||
self.url = reverse('amo.paypal')
|
||||
self.item = 1234567890
|
||||
self.client = Client()
|
||||
settings.PAYPAL_USE_EMBEDDED = True
|
||||
|
||||
def urlopener(self, status):
|
||||
m = Mock()
|
||||
|
|
|
@ -56,28 +56,32 @@ var contributions = {
|
|||
$(this).find('#contrib-too-much').show();
|
||||
return false;
|
||||
}
|
||||
if (parseFloat(amt) >= 0.01) {
|
||||
if (parseFloat(amt) < 0.01) {
|
||||
$(this).find('#contrib-too-little').show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var $self = $(this);
|
||||
$.ajax({type: 'GET',
|
||||
url: $(this).attr('action') + '?result_type=json',
|
||||
data: $(this).serialize(),
|
||||
success: function(json) {
|
||||
if (json.paykey) {
|
||||
$.getScript($('body').attr('data-paypal-url'), function() {
|
||||
dgFlow = new PAYPAL.apps.DGFlow();
|
||||
dgFlow.startFlow(json.url);
|
||||
$self.find('span.cancel a').click();
|
||||
})
|
||||
} else {
|
||||
$self.find('#paypal-error').show();
|
||||
if ($('body').attr('data-paypal-url')) {
|
||||
var $self = $(this);
|
||||
$.ajax({type: 'GET',
|
||||
url: $(this).attr('action') + '?result_type=json',
|
||||
data: $(this).serialize(),
|
||||
success: function(json) {
|
||||
if (json.paykey) {
|
||||
$.getScript($('body').attr('data-paypal-url'), function() {
|
||||
dgFlow = new PAYPAL.apps.DGFlow();
|
||||
dgFlow.startFlow(json.url);
|
||||
$self.find('span.cancel a').click();
|
||||
});
|
||||
} else {
|
||||
$self.find('#paypal-error').show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// enable overlay; make sure we have the jqm package available.
|
||||
|
|
|
@ -2,25 +2,30 @@ $(document).ready(function() {
|
|||
$("#contribute-why").popup("#contribute-more-info", {
|
||||
pointTo: "#contribute-more-info"
|
||||
});
|
||||
$('div.contribute a.suggested-amount').bind('click', function(event) {
|
||||
$.ajax({type: 'GET',
|
||||
url: $(this).attr('href') + '?result_type=json',
|
||||
success: function(json) {
|
||||
$.getScript($('body').attr('data-paypal-url'), function() {
|
||||
dgFlow = new PAYPAL.apps.DGFlow();
|
||||
dgFlow.startFlow(json.url);
|
||||
});
|
||||
}
|
||||
if ($('body').attr('data-paypal-url')) {
|
||||
$('div.contribute a.suggested-amount').bind('click', function(event) {
|
||||
$.ajax({type: 'GET',
|
||||
url: $(this).attr('href') + '?result_type=json',
|
||||
success: function(json) {
|
||||
$.getScript($('body').attr('data-paypal-url'), function() {
|
||||
dgFlow = new PAYPAL.apps.DGFlow();
|
||||
dgFlow.startFlow(json.url);
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
top_dgFlow = top.dgFlow || (top.opener && top.opener.top.dgFlow);
|
||||
if (top_dgFlow != null) {
|
||||
top_dgFlow.closeFlow();
|
||||
if (top != null) {
|
||||
top.close();
|
||||
if ($('body').attr('data-paypal-url')) {
|
||||
if ($('#paypal-result').length) {
|
||||
top_dgFlow = top.dgFlow || (top.opener && top.opener.top.dgFlow);
|
||||
if (top_dgFlow !== null) {
|
||||
top_dgFlow.closeFlow();
|
||||
if (top !== null) {
|
||||
top.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -590,6 +590,8 @@ PAYPAL_API_VERSION = '50'
|
|||
PAYPAL_APP_ID = ''
|
||||
PAYPAL_BN = ''
|
||||
PAYPAL_CGI_URL = 'https://www.paypal.com/cgi-bin/webscr'
|
||||
|
||||
PAYPAL_USE_EMBEDDED = True
|
||||
PAYPAL_PAY_URL = 'https://paypal.com/adaptivepayments/pay'
|
||||
PAYPAL_FLOW_URL = 'https://paypal.com/webapps/adaptivepayment/flow/pay'
|
||||
PAYPAL_JS_URL = 'https://www.paypalobjects.com/js/external/dg.js'
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
data-anonymous="{{ (not request.user.is_authenticated())|json }}"
|
||||
data-readonly="{{ settings.READ_ONLY|json }}"
|
||||
data-media-url="{{ MEDIA_URL }}"
|
||||
data-paypal-url="{{ settings.PAYPAL_JS_URL }}"
|
||||
{% if settings.PAYPAL_USE_EMBEDDED %}data-paypal-url="{{ settings.PAYPAL_JS_URL }}"{% endif %}
|
||||
{% block bodyattrs %}{% endblock %}>
|
||||
|
||||
{% if ADMIN_MESSAGE or settings.READ_ONLY%}
|
||||
|
|
Загрузка…
Ссылка в новой задаче