remove permissions column, the code, the views and so on (bug 864577)
This commit is contained in:
Родитель
1967f0f36a
Коммит
11a78243b6
|
@ -977,143 +977,6 @@ class NewManifestForm(happyforms.Form):
|
|||
return manifest
|
||||
|
||||
|
||||
UPSELL_CHOICES = (
|
||||
(0, _lazy("I don't have a free add-on to associate.")),
|
||||
(1, _lazy('This is a premium upgrade to:')),
|
||||
)
|
||||
APP_UPSELL_CHOICES = (
|
||||
(0, _lazy("I don't have a free app to associate.")),
|
||||
(1, _lazy('This is a premium upgrade to:')),
|
||||
)
|
||||
|
||||
|
||||
class PremiumForm(happyforms.Form):
|
||||
"""
|
||||
The premium details for an addon, which is unfortunately
|
||||
distributed across a few models.
|
||||
"""
|
||||
paypal_id = forms.CharField()
|
||||
price = forms.ModelChoiceField(queryset=Price.objects.active(),
|
||||
label=_lazy(u'Add-on price'),
|
||||
empty_label=None)
|
||||
do_upsell = forms.TypedChoiceField(coerce=lambda x: bool(int(x)),
|
||||
choices=UPSELL_CHOICES,
|
||||
widget=forms.RadioSelect(),
|
||||
required=False)
|
||||
free = forms.ModelChoiceField(queryset=Addon.objects.none(),
|
||||
required=False,
|
||||
empty_label='')
|
||||
support_email = forms.EmailField()
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
self.extra = kw.pop('extra')
|
||||
self.request = kw.pop('request')
|
||||
self.addon = self.extra['addon']
|
||||
kw['initial'] = {
|
||||
'paypal_id': self.addon.paypal_id,
|
||||
'support_email': self.addon.support_email,
|
||||
'do_upsell': 0,
|
||||
}
|
||||
if self.addon.premium:
|
||||
kw['initial']['price'] = self.addon.premium.price
|
||||
|
||||
upsell = self.addon.upsold
|
||||
if upsell:
|
||||
kw['initial'].update({
|
||||
'free': upsell.free,
|
||||
'do_upsell': 1,
|
||||
})
|
||||
|
||||
super(PremiumForm, self).__init__(*args, **kw)
|
||||
if self.addon.is_webapp():
|
||||
self.fields['price'].label = loc('App price')
|
||||
self.fields['do_upsell'].choices = APP_UPSELL_CHOICES
|
||||
self.fields['free'].queryset = (self.extra['amo_user'].addons
|
||||
.exclude(pk=self.addon.pk)
|
||||
.filter(premium_type=amo.ADDON_FREE,
|
||||
type=self.addon.type))
|
||||
|
||||
# For the wizard, we need to remove some fields.
|
||||
for field in self.extra.get('exclude', []):
|
||||
del self.fields[field]
|
||||
|
||||
def _show_token_msg(self, message):
|
||||
"""Display warning for an invalid PayPal refund token."""
|
||||
url = paypal.get_permission_url(self.addon,
|
||||
self.extra.get('dest', 'payment'),
|
||||
['REFUND'])
|
||||
msg = _(' <a href="%s">Visit PayPal to grant permission'
|
||||
' for refunds on your behalf.</a>') % url
|
||||
messages.warning(self.request, '%s %s' % (message, Markup(msg)))
|
||||
raise forms.ValidationError(message)
|
||||
|
||||
def clean_paypal_id(self):
|
||||
paypal_id = self.cleaned_data['paypal_id']
|
||||
# Check it's a valid paypal id.
|
||||
check_paypal_id(paypal_id)
|
||||
|
||||
if (self.addon.paypal_id and self.addon.paypal_id != paypal_id
|
||||
and self.addon.premium
|
||||
and self.addon.premium.has_permissions_token()):
|
||||
# If a user changes their paypal id, then we need
|
||||
# to nuke the token, but don't do this when it's is blank.
|
||||
self.addon.premium.paypal_permissions_token = ''
|
||||
self.addon.premium.save()
|
||||
|
||||
return paypal_id
|
||||
|
||||
def clean(self):
|
||||
paypal_id = self.cleaned_data.get('paypal_id', '')
|
||||
if paypal_id:
|
||||
# If we're going to prompt for refund permission, we need to
|
||||
# record the PayPal ID first.
|
||||
self.addon.paypal_id = paypal_id
|
||||
self.addon.save()
|
||||
# Check if third-party refund token is properly set up.
|
||||
no_token = (not self.addon.premium or
|
||||
not self.addon.premium.has_permissions_token())
|
||||
invalid_token = (self.addon.premium and
|
||||
not self.addon.premium.has_valid_permissions_token())
|
||||
if no_token or invalid_token:
|
||||
# L10n: We require PayPal users to have a third-party token set up.
|
||||
self._show_token_msg(loc('PayPal third-party refund token has not '
|
||||
'been set up or has recently expired.'))
|
||||
return self.cleaned_data
|
||||
|
||||
def clean_free(self):
|
||||
if self.cleaned_data['do_upsell'] and not self.cleaned_data['free']:
|
||||
raise_required()
|
||||
return self.cleaned_data['free']
|
||||
|
||||
def save(self):
|
||||
if 'paypal_id' in self.cleaned_data:
|
||||
self.addon.paypal_id = self.cleaned_data['paypal_id']
|
||||
self.addon.support_email = self.cleaned_data['support_email']
|
||||
self.addon.save()
|
||||
|
||||
if 'price' in self.cleaned_data:
|
||||
premium = self.addon.premium
|
||||
if not premium:
|
||||
premium = AddonPremium()
|
||||
premium.addon = self.addon
|
||||
premium.price = self.cleaned_data['price']
|
||||
premium.save()
|
||||
|
||||
upsell = self.addon.upsold
|
||||
if self.cleaned_data['do_upsell'] and self.cleaned_data['free']:
|
||||
|
||||
# Check if this app was already a premium version for another app.
|
||||
if upsell and upsell.free != self.cleaned_data['free']:
|
||||
upsell.delete()
|
||||
|
||||
if not upsell:
|
||||
upsell = AddonUpsell(premium=self.addon)
|
||||
upsell.free = self.cleaned_data['free']
|
||||
upsell.save()
|
||||
elif not self.cleaned_data['do_upsell'] and upsell:
|
||||
upsell.delete()
|
||||
|
||||
|
||||
def DependencyFormSet(*args, **kw):
|
||||
addon_parent = kw.pop('addon')
|
||||
|
||||
|
|
|
@ -130,58 +130,6 @@ class TestPreviewForm(amo.tests.TestCase):
|
|||
{u'image': [250, 297], u'thumbnail': [126, 150]})
|
||||
|
||||
|
||||
@mock.patch('market.models.AddonPremium.has_valid_permissions_token',
|
||||
lambda z: True)
|
||||
@mock.patch('devhub.forms.check_paypal_id', lambda z: True)
|
||||
class TestPremiumForm(amo.tests.TestCase):
|
||||
fixtures = ['base/addon_3615', 'base/users', 'market/prices']
|
||||
|
||||
def complete(self, data, exclude, dest='payment'):
|
||||
return forms.PremiumForm(data, request=None, extra={
|
||||
'addon': Addon.objects.get(pk=3615),
|
||||
'amo_user': UserProfile.objects.get(pk=999),
|
||||
'exclude': exclude,
|
||||
'dest': dest})
|
||||
|
||||
@mock.patch('devhub.forms.check_paypal_id', lambda z: True)
|
||||
@mock.patch('django.contrib.messages.warning')
|
||||
def test_remove_token(self, error):
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
addon.update(paypal_id='')
|
||||
ap = AddonPremium.objects.create(paypal_permissions_token='1',
|
||||
addon=addon, price_id=1)
|
||||
data = {'support_email': 'foo@bar.com', 'paypal_id': 'foo@bar.com'}
|
||||
form = self.complete(data, ['price'])
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
# Do not remove the token, we had no paypal_id.
|
||||
assert AddonPremium.objects.get(pk=ap.pk).paypal_permissions_token
|
||||
|
||||
data['paypal_id'] = 'fooa@bar.com'
|
||||
errmsgs = []
|
||||
error.side_effect = lambda req, msg: errmsgs.append(msg)
|
||||
form = self.complete(data, ['price'])
|
||||
# Remove the token and fail the form.
|
||||
assert not form.is_valid()
|
||||
assert not AddonPremium.objects.get(pk=ap.pk).paypal_permissions_token
|
||||
assert 'refund token' in errmsgs[0]
|
||||
eq_(len(errmsgs), 1)
|
||||
AddonPremium.objects.get(pk=ap.pk).update(paypal_permissions_token='a')
|
||||
form = self.complete(data, ['price'])
|
||||
# Do not remove the token if the paypal_id hasn't changed.
|
||||
assert form.is_valid()
|
||||
assert AddonPremium.objects.get(pk=ap.pk).paypal_permissions_token
|
||||
|
||||
def test_no_paypal_id(self):
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
addon.update(paypal_id='some@id.com')
|
||||
AddonPremium.objects.create(paypal_permissions_token='1',
|
||||
addon=addon)
|
||||
form = self.complete({}, ['paypal_id', 'support_email'])
|
||||
assert not form.is_valid()
|
||||
eq_(['price'], form.errors.keys())
|
||||
|
||||
|
||||
class TestThemeForm(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/user_2519']
|
||||
|
||||
|
|
|
@ -656,15 +656,6 @@ class TestEditPayments(amo.tests.TestCase):
|
|||
eq_('You cannot enroll in the Marketplace' in doc('p.error').text(),
|
||||
True)
|
||||
|
||||
@mock.patch.dict(jingo.env.globals['waffle'], {'switch': lambda x: True})
|
||||
def test_addon_not_reviewed(self):
|
||||
self.get_addon().update(status=amo.STATUS_NULL,
|
||||
highest_status=amo.STATUS_NULL)
|
||||
res = self.client.get(self.url)
|
||||
doc = pq(res.content)
|
||||
eq_(doc('#do-marketplace').text(), 'Enroll in Marketplace')
|
||||
eq_('fully reviewed add-ons' in doc('p.error').text(), True)
|
||||
|
||||
@mock.patch('addons.models.Addon.upsell')
|
||||
def test_upsell(self, upsell):
|
||||
upsell.return_value = self.get_addon()
|
||||
|
@ -871,278 +862,6 @@ class MarketplaceMixin(object):
|
|||
paypal_id='a@a.com')
|
||||
|
||||
|
||||
class TestRefundToken(MarketplaceMixin, amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615']
|
||||
|
||||
def test_no_token(self):
|
||||
self.setup_premium()
|
||||
res = self.client.post(self.url, {"paypal_id": "a@a.com",
|
||||
"support_email": "dev@example.com"})
|
||||
assert 'refund token' in pq(res.content)('.notification-box')[0].text
|
||||
|
||||
@mock.patch('paypal.check_permission')
|
||||
def test_with_token(self, cp):
|
||||
cp.return_value = True
|
||||
self.setup_premium()
|
||||
self.addon.addonpremium.update(paypal_permissions_token='foo')
|
||||
res = self.client.post(self.url, {"paypal_id": "a@a.com",
|
||||
"support_email": "dev@example.com"})
|
||||
assert not pq(res.content)('.notification-box')
|
||||
|
||||
|
||||
# Mock out verfiying the paypal id has refund permissions with paypal and
|
||||
# that the account exists on paypal.
|
||||
#
|
||||
@mock.patch('devhub.forms.PremiumForm.clean_paypal_id',
|
||||
new=lambda x: x.cleaned_data['paypal_id'])
|
||||
@mock.patch('devhub.forms.PremiumForm.clean', new=lambda x: x.cleaned_data)
|
||||
class TestMarketplace(MarketplaceMixin, amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/addon_3615']
|
||||
|
||||
@mock.patch('addons.models.Addon.can_become_premium')
|
||||
def test_ask_page(self, can_become_premium):
|
||||
can_become_premium.return_value = True
|
||||
res = self.client.get(self.url)
|
||||
eq_(res.status_code, 200)
|
||||
doc = pq(res.content)
|
||||
eq_(len(doc('div.intro')), 2)
|
||||
|
||||
@mock.patch('addons.models.Addon.can_become_premium')
|
||||
def test_no_warning(self, can_become_premium):
|
||||
can_become_premium.return_value = True
|
||||
doc = pq(self.client.get(self.url).content)
|
||||
eq_(len(doc('div.notification-box')), 0)
|
||||
|
||||
@mock.patch('addons.models.Addon.can_become_premium')
|
||||
def test_warning(self, can_become_premium):
|
||||
can_become_premium.return_value = True
|
||||
self.addon.update(status=amo.STATUS_UNREVIEWED)
|
||||
doc = pq(self.client.get(self.url).content)
|
||||
eq_(len(doc('div.notification-box')), 1)
|
||||
|
||||
@mock.patch('addons.models.Addon.can_become_premium')
|
||||
def test_cant_become_premium(self, can_become_premium):
|
||||
can_become_premium.return_value = False
|
||||
res = self.client.get(self.url)
|
||||
eq_(res.status_code, 200)
|
||||
doc = pq(res.content)
|
||||
eq_(len(doc('.error')), 2)
|
||||
|
||||
@mock.patch('addons.models.Addon.upsell')
|
||||
def test_addon_upsell(self, upsell):
|
||||
upsell.return_value = True
|
||||
res = self.client.get(self.url)
|
||||
doc = pq(res.content)
|
||||
assert 'You cannot enroll in the Marketplace' in doc('p.error').text()
|
||||
|
||||
def get_data(self):
|
||||
return {
|
||||
'paypal_id': 'a@a.com',
|
||||
'price': self.price.pk,
|
||||
'free': self.other_addon.pk,
|
||||
'support_email': 'b@b.com',
|
||||
'do_upsell': 1,
|
||||
'text': 'some upsell',
|
||||
}
|
||||
|
||||
def test_template_premium(self):
|
||||
self.setup_premium()
|
||||
res = self.client.get(self.url)
|
||||
self.assertTemplateUsed(res, 'devhub/payments/premium.html')
|
||||
|
||||
def test_template_free(self):
|
||||
res = self.client.get(self.url)
|
||||
self.assertTemplateUsed(res, 'devhub/payments/payments.html')
|
||||
|
||||
def test_initial(self):
|
||||
self.setup_premium()
|
||||
res = self.client.get(self.url)
|
||||
eq_(res.status_code, 200)
|
||||
eq_(res.context['form'].initial['price'], self.price)
|
||||
eq_(res.context['form'].initial['paypal_id'], 'a@a.com')
|
||||
|
||||
def test_set(self):
|
||||
self.setup_premium()
|
||||
res = self.client.post(self.url, data={
|
||||
'paypal_id': 'b@b.com',
|
||||
'support_email': 'c@c.com',
|
||||
'price': self.price_two.pk,
|
||||
})
|
||||
eq_(res.status_code, 302)
|
||||
self.addon = Addon.objects.get(pk=self.addon.pk)
|
||||
eq_(self.addon.paypal_id, 'b@b.com')
|
||||
eq_(self.addon.addonpremium.price, self.price_two)
|
||||
|
||||
def test_no_free(self):
|
||||
self.setup_premium()
|
||||
self.other_addon.authors.clear()
|
||||
res = self.client.get(self.url)
|
||||
assert not pq(res.content)('#id_free')
|
||||
|
||||
@mock.patch('paypal.get_permissions_token', lambda x, y: x.upper())
|
||||
def test_permissions_token(self):
|
||||
self.setup_premium()
|
||||
eq_(self.addon.premium.paypal_permissions_token, '')
|
||||
url = self.addon.get_dev_url('acquire_refund_permission')
|
||||
data = {'request_token': 'foo', 'verification_code': 'bar'}
|
||||
self.client.get('%s?%s' % (url, urlencode(data)))
|
||||
self.addon = Addon.objects.get(pk=self.addon.pk)
|
||||
eq_(self.addon.premium.paypal_permissions_token, 'FOO')
|
||||
|
||||
@mock.patch('paypal.get_permissions_token', lambda x, y: x.upper())
|
||||
def test_permissions_token_redirect(self):
|
||||
self.setup_premium()
|
||||
eq_(self.addon.premium.paypal_permissions_token, '')
|
||||
url = reverse('devhub.addons.acquire_refund_permission',
|
||||
args=[self.addon.slug])
|
||||
data = {'request_token': 'foo', 'verification_code': 'bar'}
|
||||
res = self.client.get(url, data=data)
|
||||
assert res['Location'].endswith(reverse('devhub.addons.payments',
|
||||
args=[self.addon.slug]))
|
||||
|
||||
data['dest'] = 'wizard'
|
||||
res = self.client.get(url, data=data)
|
||||
assert res['Location'].endswith(reverse('devhub.addons.market.1',
|
||||
args=[self.addon.slug]))
|
||||
|
||||
@mock.patch('paypal.get_permissions_token', lambda x, y: x.upper())
|
||||
def test_permissions_token_no_premium(self):
|
||||
self.setup_premium()
|
||||
# They could hit this URL before anything else, we need to cope
|
||||
# with AddonPremium not being there.
|
||||
self.addon.premium.delete()
|
||||
self.addon.update(premium_type=amo.ADDON_FREE)
|
||||
url = self.addon.get_dev_url('acquire_refund_permission')
|
||||
data = {'request_token': 'foo', 'verification_code': 'bar'}
|
||||
self.client.get('%s?%s' % (url, urlencode(data)))
|
||||
self.addon = Addon.objects.get(pk=self.addon.pk)
|
||||
eq_(self.addon.addonpremium.paypal_permissions_token, 'FOO')
|
||||
|
||||
def test_wizard_step_1(self):
|
||||
url = self.addon.get_dev_url('market.1')
|
||||
data = {'paypal_id': 'some@paypal.com', 'support_email': 'a@a.com'}
|
||||
eq_(self.client.post(url, data).status_code, 302)
|
||||
addon = Addon.objects.get(pk=self.addon.pk)
|
||||
eq_(addon.paypal_id, data['paypal_id'])
|
||||
eq_(addon.support_email, data['support_email'])
|
||||
|
||||
def test_wizard_step_1_required_paypal(self):
|
||||
url = self.addon.get_dev_url('market.1')
|
||||
data = {'paypal_id': '', 'support_email': 'a@a.com'}
|
||||
eq_(self.client.post(url, data).status_code, 200)
|
||||
|
||||
@mock.patch('devhub.forms.PremiumForm.clean_paypal_id')
|
||||
def test_wizard_step_1_required_email(self, clean_paypal_id):
|
||||
url = self.addon.get_dev_url('market.1')
|
||||
data = {'paypal_id': 'a@a.com', 'support_email': ''}
|
||||
clean_paypal_id.return_value = data['support_email']
|
||||
eq_(self.client.post(url, data).status_code, 200)
|
||||
|
||||
def test_wizard_step_2(self):
|
||||
self.price = Price.objects.create(price='0.99')
|
||||
url = self.addon.get_dev_url('market.2')
|
||||
eq_(self.client.post(url, {'price': self.price.pk}).status_code, 302)
|
||||
eq_(Addon.objects.get(pk=self.addon.pk).premium.price.pk,
|
||||
self.price.pk)
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.get(pk=self.addon.pk)
|
||||
|
||||
def add_addon_author(self, type):
|
||||
addon = Addon.objects.create(type=amo.ADDON_EXTENSION,
|
||||
premium_type=type)
|
||||
AddonUser.objects.create(addon=addon,
|
||||
user=self.addon.authors.all()[0])
|
||||
return addon
|
||||
|
||||
def test_wizard_step_3(self):
|
||||
self.setup_premium()
|
||||
url = self.addon.get_dev_url('market.3')
|
||||
self.other_addon = self.add_addon_author(amo.ADDON_FREE)
|
||||
data = {
|
||||
'free': self.other_addon.pk,
|
||||
'do_upsell': 1,
|
||||
'text': 'some upsell',
|
||||
}
|
||||
eq_(self.client.post(url, data).status_code, 302)
|
||||
eq_(self.get_addon().upsold.free, self.other_addon)
|
||||
|
||||
def test_form_only_free(self):
|
||||
self.premium = self.add_addon_author(amo.ADDON_PREMIUM)
|
||||
self.free = self.add_addon_author(amo.ADDON_FREE)
|
||||
url = self.addon.get_dev_url('market.3')
|
||||
res = self.client.get(url)
|
||||
upsell = res.context['form'].fields['free'].queryset.all()
|
||||
assert self.free in upsell
|
||||
assert self.premium not in upsell
|
||||
|
||||
def test_wizard_no_free(self):
|
||||
self.price = Price.objects.create(price='0.99')
|
||||
url = self.addon.get_dev_url('market.2')
|
||||
res = self.client.post(url, {'price': self.price.pk})
|
||||
self.assertRedirects(res, self.addon.get_dev_url('market.4'))
|
||||
|
||||
def test_wizard_step_4_failed(self):
|
||||
url = self.addon.get_dev_url('market.4')
|
||||
assert not self.get_addon().is_premium()
|
||||
eq_(self.client.post(url, {}).status_code, 302)
|
||||
assert not self.get_addon().is_premium()
|
||||
|
||||
def test_wizard_step_4(self):
|
||||
self.setup_premium()
|
||||
self.addon.premium.update(paypal_permissions_token='foo')
|
||||
self.addon.update(premium_type=amo.ADDON_FREE)
|
||||
url = self.addon.get_dev_url('market.4')
|
||||
eq_(self.client.post(url, {}).status_code, 302)
|
||||
assert self.get_addon().is_premium()
|
||||
|
||||
@mock.patch('addons.models.Addon.upsell')
|
||||
def test_wizard_step_4_fails(self, upsell):
|
||||
upsell.return_value = True
|
||||
url = self.addon.get_dev_url('market.4')
|
||||
eq_(self.client.post(url, {}).status_code, 403)
|
||||
assert not self.get_addon().is_premium()
|
||||
|
||||
def test_wizard_step_4_status(self):
|
||||
self.setup_premium()
|
||||
self.addon.premium.update(paypal_permissions_token='foo')
|
||||
self.addon.update(status=amo.STATUS_UNREVIEWED)
|
||||
url = self.addon.get_dev_url('market.4')
|
||||
self.client.post(url, {})
|
||||
eq_(self.get_addon().status, amo.STATUS_NOMINATED)
|
||||
|
||||
def test_logs(self):
|
||||
self.setup_premium()
|
||||
self.addon.premium.update(paypal_permissions_token='foo')
|
||||
url = self.addon.get_dev_url('market.4')
|
||||
eq_(self.client.post(url, {}).status_code, 302)
|
||||
eq_(ActivityLog.objects.for_addons(self.addon)[0].action,
|
||||
amo.LOG.MAKE_PREMIUM.id)
|
||||
|
||||
def test_can_edit(self):
|
||||
self.setup_premium()
|
||||
assert 'no-edit' not in self.client.get(self.url).content
|
||||
|
||||
def test_wizard_denied(self):
|
||||
self.addon.update(status=amo.STATUS_PUBLIC)
|
||||
for x in xrange(1, 5):
|
||||
res = self.client.get(self.addon.get_dev_url('market.%s' % x))
|
||||
eq_(res.status_code, 403)
|
||||
|
||||
def test_no_delete_link_premium_addon(self):
|
||||
self.setup_premium()
|
||||
doc = pq(self.client.get(self.addon.get_dev_url('versions')).content)
|
||||
eq_(len(doc('#delete-addon')), 0)
|
||||
|
||||
def test_no_delete_premium_addon(self):
|
||||
self.setup_premium()
|
||||
res = self.client.post(self.addon.get_dev_url('delete'),
|
||||
{'password': 'password'})
|
||||
eq_(res.status_code, 302)
|
||||
assert Addon.objects.filter(pk=self.addon.id).exists(), (
|
||||
"Unexpected: Addon should exist")
|
||||
|
||||
|
||||
class TestIssueRefund(amo.tests.TestCase):
|
||||
fixtures = ('base/users', 'base/addon_3615')
|
||||
|
||||
|
|
|
@ -31,18 +31,6 @@ submit_apps_patterns = patterns('',
|
|||
)
|
||||
|
||||
|
||||
def marketplace_patterns(prefix):
|
||||
return patterns('',
|
||||
url('^1$', views.marketplace_paypal,
|
||||
name='devhub.%s.market.1' % prefix),
|
||||
url('^2$', views.marketplace_pricing,
|
||||
name='devhub.%s.market.2' % prefix),
|
||||
url('^3$', views.marketplace_upsell,
|
||||
name='devhub.%s.market.3' % prefix),
|
||||
url('^4$', views.marketplace_confirm,
|
||||
name='devhub.%s.market.4' % prefix),
|
||||
)
|
||||
|
||||
# These will all start with /theme/<slug>/
|
||||
theme_detail_patterns = patterns('',
|
||||
url('^$', lambda r,
|
||||
|
@ -61,12 +49,6 @@ app_detail_patterns = patterns('',
|
|||
url('^delete$', views.delete, name='devhub.apps.delete'),
|
||||
url('^disable$', views.disable, name='devhub.apps.disable'),
|
||||
url('^status$', views.version_list, name='devhub.apps.versions'),
|
||||
url('^payments$', views.payments, name='devhub.apps.payments'),
|
||||
url('^payments/disable$', views.disable_payments,
|
||||
name='devhub.apps.payments.disable'),
|
||||
url('^payments/permission/refund$', views.acquire_refund_permission,
|
||||
name='devhub.apps.acquire_refund_permission'),
|
||||
url('^payments/', include(marketplace_patterns('apps'))),
|
||||
url('^profile$', views.profile, name='devhub.apps.profile'),
|
||||
url('^profile/remove$', views.remove_profile,
|
||||
name='devhub.apps.profile.remove'),
|
||||
|
@ -90,9 +72,6 @@ detail_patterns = patterns('',
|
|||
url('^payments$', views.payments, name='devhub.addons.payments'),
|
||||
url('^payments/disable$', views.disable_payments,
|
||||
name='devhub.addons.payments.disable'),
|
||||
url('^payments/permission/refund$', views.acquire_refund_permission,
|
||||
name='devhub.addons.acquire_refund_permission'),
|
||||
url('^payments/', include(marketplace_patterns('addons'))),
|
||||
url('^issue_refund$', views.issue_refund,
|
||||
name='devhub.addons.issue_refund'),
|
||||
url('^refunds$', views.refunds, name='devhub.addons.refunds'),
|
||||
|
|
|
@ -541,33 +541,6 @@ def _save_charity(addon, contrib_form, charity_form):
|
|||
return True
|
||||
|
||||
|
||||
@write
|
||||
@dev_required(webapp=True)
|
||||
def acquire_refund_permission(request, addon_id, addon, webapp=False):
|
||||
"""This is the callback from Paypal."""
|
||||
paypal_log.debug('User approved refund for addon: %s' % addon_id)
|
||||
token = paypal.get_permissions_token(request.GET['request_token'],
|
||||
request.GET['verification_code'])
|
||||
paypal_log.debug('Got refund token for addon: %s, token: %s....' %
|
||||
(addon_id, token[:10]))
|
||||
|
||||
# Sadly this is an update on a GET.
|
||||
addonpremium, created = (AddonPremium.objects
|
||||
.safer_get_or_create(addon=addon))
|
||||
|
||||
paypal_log.debug('AddonPremium %s for: %s' %
|
||||
('created' if created else 'updated', addon.pk))
|
||||
addonpremium.update(paypal_permissions_token=token)
|
||||
|
||||
paypal_log.debug('AddonPremium saved with token: %s' % addonpremium.pk)
|
||||
amo.log(amo.LOG.EDIT_PROPERTIES, addon)
|
||||
|
||||
dest = 'payments'
|
||||
if request.GET.get('dest') == 'wizard':
|
||||
dest = 'market.1'
|
||||
return redirect(addon.get_dev_url(dest))
|
||||
|
||||
|
||||
@waffle_switch('allow-refund')
|
||||
@dev_required(webapp=True)
|
||||
def issue_refund(request, addon_id, addon, webapp=False):
|
||||
|
@ -1516,89 +1489,6 @@ def submit_step(outer_step):
|
|||
return decorator
|
||||
|
||||
|
||||
@dev_required(webapp=True)
|
||||
@can_become_premium
|
||||
def marketplace_paypal(request, addon_id, addon, webapp=False):
|
||||
"""
|
||||
Start of the marketplace wizard, none of this means anything until
|
||||
addon-premium is set, so we'll just save as we go along. Further
|
||||
we might have the PayPal permissions bounce happen at any time
|
||||
so we'll need to cope with AddonPremium being incomplete.
|
||||
"""
|
||||
form = forms.PremiumForm(request.POST or None,
|
||||
request=request,
|
||||
extra={'addon': addon,
|
||||
'amo_user': request.amo_user,
|
||||
'dest': 'wizard',
|
||||
'exclude': ['price']})
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect(addon.get_dev_url('market.2'))
|
||||
|
||||
return jingo.render(request, 'devhub/payments/paypal.html',
|
||||
{'form': form, 'addon': addon, 'webapp': webapp,
|
||||
'premium': addon.premium})
|
||||
|
||||
|
||||
@dev_required(webapp=True)
|
||||
@can_become_premium
|
||||
def marketplace_pricing(request, addon_id, addon, webapp=False):
|
||||
form = forms.PremiumForm(request.POST or None,
|
||||
request=request,
|
||||
extra={'addon': addon,
|
||||
'amo_user': request.amo_user,
|
||||
'dest': 'wizard',
|
||||
'exclude': ['paypal_id',
|
||||
'support_email']})
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
if not (form.fields['free'].queryset.count()):
|
||||
return redirect(addon.get_dev_url('market.4'))
|
||||
return redirect(addon.get_dev_url('market.3'))
|
||||
return jingo.render(request, 'devhub/payments/tier.html',
|
||||
{'form': form, 'addon': addon, 'webapp': webapp,
|
||||
'premium': addon.premium})
|
||||
|
||||
|
||||
@dev_required(webapp=True)
|
||||
@can_become_premium
|
||||
def marketplace_upsell(request, addon_id, addon, webapp=False):
|
||||
form = forms.PremiumForm(request.POST or None,
|
||||
request=request,
|
||||
extra={'addon': addon,
|
||||
'amo_user': request.amo_user,
|
||||
'dest': 'wizard',
|
||||
'exclude': ['price', 'paypal_id',
|
||||
'support_email']})
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect(addon.get_dev_url('market.4'))
|
||||
return jingo.render(request, 'devhub/payments/upsell.html',
|
||||
{'form': form, 'addon': addon, 'webapp': webapp,
|
||||
'premium': addon.premium})
|
||||
|
||||
|
||||
@dev_required(webapp=True)
|
||||
@can_become_premium
|
||||
def marketplace_confirm(request, addon_id, addon, webapp=False):
|
||||
if request.method == 'POST':
|
||||
if (addon.premium and addon.premium.is_complete()
|
||||
and addon.premium.has_permissions_token()):
|
||||
if addon.status == amo.STATUS_UNREVIEWED:
|
||||
addon.status = amo.STATUS_NOMINATED
|
||||
addon.premium_type = amo.ADDON_PREMIUM
|
||||
addon.save()
|
||||
amo.log(amo.LOG.MAKE_PREMIUM, addon)
|
||||
return redirect(addon.get_dev_url('payments'))
|
||||
|
||||
messages.error(request, 'Some required details are missing.')
|
||||
return redirect(addon.get_dev_url('market.1'))
|
||||
|
||||
return jingo.render(request, 'devhub/payments/second-confirm.html',
|
||||
{'addon': addon, 'webapp': webapp,
|
||||
'upsell': addon.upsold, 'premium': addon.premium})
|
||||
|
||||
|
||||
def _step_url(step, is_webapp):
|
||||
url_base = 'devhub.submit%s' % ('_apps' if is_webapp else '')
|
||||
if is_webapp and str(step).isdigit() and step > 5:
|
||||
|
|
|
@ -204,7 +204,6 @@ class AddonPremium(amo.models.ModelBase):
|
|||
"""Additions to the Addon model that only apply to Premium add-ons."""
|
||||
addon = models.OneToOneField('addons.Addon')
|
||||
price = models.ForeignKey(Price, blank=True, null=True)
|
||||
paypal_permissions_token = models.CharField(max_length=255, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'addons_premium'
|
||||
|
@ -230,26 +229,6 @@ class AddonPremium(amo.models.ModelBase):
|
|||
return bool(self.addon and self.price and
|
||||
self.addon.paypal_id and self.addon.support_email)
|
||||
|
||||
def has_permissions_token(self):
|
||||
"""
|
||||
Have we got a permissions token. If you've got 'should_ignore_paypal'
|
||||
enabled, then it will just happily return True.
|
||||
"""
|
||||
return bool(paypal.should_ignore_paypal() or
|
||||
self.paypal_permissions_token)
|
||||
|
||||
def has_valid_permissions_token(self):
|
||||
"""
|
||||
Have we got a valid permissions token by pinging PayPal. If you've got
|
||||
'should_ignore_paypal', then it will just happily return True.
|
||||
"""
|
||||
if paypal.should_ignore_paypal():
|
||||
return True
|
||||
if not self.paypal_permissions_token:
|
||||
return False
|
||||
return paypal.check_permission(self.paypal_permissions_token,
|
||||
['REFUND'])
|
||||
|
||||
def supported_currencies(self):
|
||||
"""A hook for currency filtering."""
|
||||
return self.price.currencies()
|
||||
|
|
|
@ -38,36 +38,6 @@ class TestPremium(amo.tests.TestCase):
|
|||
self.tier_one.update(price=Decimal('0.00'))
|
||||
eq_(ap.has_price(), False)
|
||||
|
||||
@mock.patch('paypal.should_ignore_paypal', lambda: False)
|
||||
def test_has_permissions_token(self):
|
||||
ap = AddonPremium(addon=self.addon)
|
||||
assert not ap.has_permissions_token()
|
||||
ap.paypal_permissions_token = 'asd'
|
||||
assert ap.has_permissions_token()
|
||||
|
||||
@mock.patch('paypal.should_ignore_paypal', lambda: True)
|
||||
def test_has_permissions_token_ignore(self):
|
||||
ap = AddonPremium(addon=self.addon)
|
||||
assert ap.has_permissions_token()
|
||||
ap.paypal_permissions_token = 'asd'
|
||||
assert ap.has_permissions_token()
|
||||
|
||||
@mock.patch('paypal.should_ignore_paypal', lambda: False)
|
||||
@mock.patch('paypal.check_permission')
|
||||
def test_has_valid_permissions_token(self, check_permission):
|
||||
ap = AddonPremium(addon=self.addon)
|
||||
assert not ap.has_valid_permissions_token()
|
||||
check_permission.return_value = True
|
||||
ap.paypal_permissions_token = 'some_token'
|
||||
assert ap.has_valid_permissions_token()
|
||||
|
||||
@mock.patch('paypal.should_ignore_paypal', lambda: True)
|
||||
def test_has_valid_permissions_token_ignore(self):
|
||||
ap = AddonPremium(addon=self.addon)
|
||||
assert ap.has_valid_permissions_token()
|
||||
ap.paypal_permissions_token = 'asd'
|
||||
assert ap.has_valid_permissions_token()
|
||||
|
||||
def test_price_locale(self):
|
||||
ap = AddonPremium(addon=self.addon, price=self.tier_one)
|
||||
eq_(ap.get_price_locale('CAD'), 'CA$3.01')
|
||||
|
|
|
@ -328,84 +328,6 @@ def get_personal_data(token):
|
|||
return result
|
||||
|
||||
|
||||
def check_permission(token, permissions):
|
||||
"""
|
||||
Asks PayPal whether the PayPal ID for this account has granted
|
||||
the permissions requested to us. Permissions are strings from the
|
||||
PayPal documentation.
|
||||
Documentation: http://bit.ly/zlhXlT
|
||||
|
||||
"""
|
||||
# This is set in settings_test so we don't start calling PayPal
|
||||
# by accident. Explicitly set this in your tests.
|
||||
if not settings.PAYPAL_PERMISSIONS_URL:
|
||||
return False
|
||||
paypal_log.debug('Checking refund permission for token: %s..'
|
||||
% token[:10])
|
||||
try:
|
||||
with statsd.timer('paypal.permissions.refund'):
|
||||
r = _call(settings.PAYPAL_PERMISSIONS_URL + 'GetPermissions',
|
||||
{'token': urlparse.parse_qs(token)['token']})
|
||||
except PaypalError, error:
|
||||
paypal_log.debug('Paypal returned error for token: %s.. error: %s'
|
||||
% (token[:10], error))
|
||||
return False
|
||||
# in the future we may ask for other permissions so let's just
|
||||
# make sure REFUND is one of them.
|
||||
paypal_log.debug('Paypal returned permissions for token: %s.. perms: %s'
|
||||
% (token[:10], r))
|
||||
result = [v for (k, v) in r.iteritems() if k.startswith('scope')]
|
||||
return set(permissions).issubset(set(result))
|
||||
|
||||
|
||||
def get_permission_url(addon, dest, scope):
|
||||
"""
|
||||
Send permissions request to PayPal for privileges on
|
||||
this PayPal account. Returns URL on PayPal site to visit.
|
||||
Documentation: http://bit.ly/zlhXlT
|
||||
"""
|
||||
# This is set in settings_test so we don't start calling PayPal
|
||||
# by accident. Explicitly set this in your tests.
|
||||
if not settings.PAYPAL_PERMISSIONS_URL:
|
||||
return ''
|
||||
|
||||
paypal_log.debug('Getting refund permission URL for addon: %s' % addon.pk)
|
||||
|
||||
with statsd.timer('paypal.permissions.url'):
|
||||
url = urlparams(addon.get_dev_url('acquire_refund_permission'),
|
||||
dest=dest)
|
||||
try:
|
||||
r = _call(settings.PAYPAL_PERMISSIONS_URL + 'RequestPermissions',
|
||||
{'scope': scope, 'callback': absolutify(url)})
|
||||
except PaypalError, e:
|
||||
paypal_log.debug('Error on refund permission URL addon: %s, %s' %
|
||||
(addon.pk, e))
|
||||
if e.id == '580028':
|
||||
# PayPal is very picky about where they redirect users to.
|
||||
# If you try and create a PayPal permissions URL on a
|
||||
# zamboni that has a non-standard port number or a
|
||||
# non-standard TLD, it will blow up with an error. We need
|
||||
# to be able to at least visit these pages and alter them
|
||||
# in dev, so this will give you a broken token that doesn't
|
||||
# work, but at least the page will function.
|
||||
r = {'token': 'wont-work-paypal-doesnt-like-your-domain'}
|
||||
else:
|
||||
raise
|
||||
return (settings.PAYPAL_CGI_URL +
|
||||
'?cmd=_grant-permission&request_token=%s' % r['token'])
|
||||
|
||||
|
||||
def get_permissions_token(request_token, verification_code):
|
||||
"""
|
||||
Send request for permissions token, after user has granted the
|
||||
requested permissions via the PayPal page we redirected them to.
|
||||
"""
|
||||
with statsd.timer('paypal.permissions.token'):
|
||||
r = _call(settings.PAYPAL_PERMISSIONS_URL + 'GetAccessToken',
|
||||
{'token': request_token, 'verifier': verification_code})
|
||||
return urllib.urlencode({'token': r['token'], 'secret': r['tokenSecret']})
|
||||
|
||||
|
||||
def get_preapproval_key(data):
|
||||
"""
|
||||
Get a preapproval key from PayPal. If this passes, you get a key that
|
||||
|
|
|
@ -74,25 +74,6 @@ class Check(object):
|
|||
self.failure(test_id, msg)
|
||||
return
|
||||
|
||||
token = premium.paypal_permissions_token
|
||||
if not token:
|
||||
self.state['permissions'] = False
|
||||
self.failure(test_id, msg)
|
||||
return
|
||||
|
||||
try:
|
||||
status = paypal.check_permission(token, ['REFUND'])
|
||||
if not status:
|
||||
self.state['permissions'] = False
|
||||
self.failure(test_id, _('No permission to do refunds.'))
|
||||
else:
|
||||
self.pass_(test_id)
|
||||
except paypal.PaypalError:
|
||||
self.state['permissions'] = False
|
||||
self.failure(test_id, msg)
|
||||
log.info('Refund permission check returned an error '
|
||||
'for %s' % id, exc_info=True)
|
||||
|
||||
def check_currencies(self):
|
||||
"""Check that we've got the currencies."""
|
||||
test_id = 'currencies'
|
||||
|
|
|
@ -291,75 +291,6 @@ def test_nvp():
|
|||
eq_(paypal._nvp_dump({'foo': ['bar', 'baa']}), 'foo(0)=bar&foo(1)=baa')
|
||||
|
||||
|
||||
@mock.patch('paypal._call')
|
||||
@mock.patch.object(settings, 'PAYPAL_PERMISSIONS_URL', 'something')
|
||||
class TestRefundPermissions(amo.tests.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.addon = Addon(type=amo.ADDON_EXTENSION, slug='foo')
|
||||
|
||||
def test_get_permissions_url(self, _call):
|
||||
"""
|
||||
`paypal_get_permission_url` returns an URL for PayPal's
|
||||
permissions request service containing the token PayPal gives
|
||||
us.
|
||||
"""
|
||||
_call.return_value = {'token': 'foo'}
|
||||
assert 'foo' in paypal.get_permission_url(self.addon, '', [])
|
||||
|
||||
def test_get_permissions_url_settings(self, _call):
|
||||
settings.PAYPAL_PERMISSIONS_URL = ''
|
||||
assert not paypal.get_permission_url(self.addon, '', [])
|
||||
|
||||
def test_get_permissions_url_malformed(self, _call):
|
||||
_call.side_effect = paypal.PaypalError(id='580028')
|
||||
assert 'wont-work' in paypal.get_permission_url(self.addon, '', [])
|
||||
|
||||
def test_get_permissions_url_error(self, _call):
|
||||
_call.side_effect = paypal.PaypalError
|
||||
with self.assertRaises(paypal.PaypalError):
|
||||
paypal.get_permission_url(self.addon, '', [])
|
||||
|
||||
def test_get_permissions_url_scope(self, _call):
|
||||
_call.return_value = {'token': 'foo', 'tokenSecret': 'bar'}
|
||||
paypal.get_permission_url(self.addon, '', ['REFUND', 'FOO'])
|
||||
eq_(_call.call_args[0][1]['scope'], ['REFUND', 'FOO'])
|
||||
|
||||
def test_check_permission_fail(self, _call):
|
||||
"""
|
||||
`check_paypal_refund_permission` returns False if PayPal
|
||||
doesn't put 'REFUND' in the permissions response.
|
||||
"""
|
||||
_call.return_value = {'scope(0)': 'HAM_SANDWICH'}
|
||||
assert not paypal.check_permission(good_token, ['REFUND'])
|
||||
|
||||
def test_check_permission(self, _call):
|
||||
"""
|
||||
`check_paypal_refund_permission` returns True if PayPal
|
||||
puts 'REFUND' in the permissions response.
|
||||
"""
|
||||
_call.return_value = {'scope(0)': 'REFUND'}
|
||||
eq_(paypal.check_permission(good_token, ['REFUND']), True)
|
||||
|
||||
def test_check_permission_error(self, _call):
|
||||
_call.side_effect = paypal.PaypalError
|
||||
assert not paypal.check_permission(good_token, ['REFUND'])
|
||||
|
||||
def test_check_permission_settings(self, _call):
|
||||
settings.PAYPAL_PERMISSIONS_URL = ''
|
||||
assert not paypal.check_permission(good_token, ['REFUND'])
|
||||
|
||||
def test_get_permissions_token(self, _call):
|
||||
_call.return_value = {'token': 'foo', 'tokenSecret': 'bar'}
|
||||
eq_(paypal.get_permissions_token('foo', ''), good_token)
|
||||
|
||||
def test_get_permissions_subset(self, _call):
|
||||
_call.return_value = {'scope(0)': 'REFUND', 'scope(1)': 'HAM'}
|
||||
eq_(paypal.check_permission(good_token, ['REFUND', 'HAM']), True)
|
||||
eq_(paypal.check_permission(good_token, ['REFUND', 'JAM']), False)
|
||||
eq_(paypal.check_permission(good_token, ['REFUND']), True)
|
||||
|
||||
|
||||
good_refund_string = (
|
||||
'refundInfoList.refundInfo(0).receiver.amount=123.45'
|
||||
'&refundInfoList.refundInfo(0).receiver.email=bob@example.com'
|
||||
|
|
|
@ -49,28 +49,6 @@ class TestCheck(amo.tests.TestCase):
|
|||
self.check.check_id()
|
||||
assert not self.check.passed, self.check.state
|
||||
|
||||
@patch('paypal.check_permission')
|
||||
def test_check_refund(self, check_permission):
|
||||
check_permission.return_value = True
|
||||
self.check.check_refund()
|
||||
assert self.check.passed, self.check.state
|
||||
|
||||
@patch('paypal.check_permission')
|
||||
def test_check_refund_fails(self, check_permission):
|
||||
check_permission.return_value = False
|
||||
self.check.check_refund()
|
||||
assert not self.check.passed, self.check.state
|
||||
|
||||
def test_check_refund_no_token(self):
|
||||
self.addon.premium.paypal_permission_token = ''
|
||||
self.check.check_refund()
|
||||
assert not self.check.passed, self.check.state
|
||||
|
||||
def test_check_refund_no_premium(self):
|
||||
self.addon.premium = None
|
||||
self.check.check_refund()
|
||||
assert not self.check.passed, self.check.state
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_check_paykey(self, get_paykey):
|
||||
self.check.check_currencies()
|
||||
|
|
|
@ -226,6 +226,7 @@ class TestPaypalSolitude(PaypalTest):
|
|||
|
||||
@patch('paypal.views.requests.post')
|
||||
class TestPaypal(PaypalTest):
|
||||
fixtures = ['base/users']
|
||||
|
||||
def test_not_verified(self, urlopen):
|
||||
urlopen.return_value = self.urlopener('xxx')
|
||||
|
@ -298,7 +299,8 @@ class TestPaypal(PaypalTest):
|
|||
urlopen.return_value = self.urlopener('VERIFIED')
|
||||
add = Addon.objects.create(type=amo.ADDON_EXTENSION)
|
||||
con = Contribution.objects.create(addon_id=add.pk,
|
||||
transaction_id=sample_contribution['tracking_id'])
|
||||
transaction_id=sample_contribution['tracking_id'],
|
||||
user=UserProfile.objects.all()[0])
|
||||
|
||||
for type_ in [amo.CONTRIB_VOLUNTARY, amo.CONTRIB_PURCHASE]:
|
||||
con.update(type=type_)
|
||||
|
|
|
@ -81,8 +81,6 @@ database:
|
|||
- average_daily_downloads
|
||||
- average_daily_users
|
||||
- total_contributions
|
||||
addons_premium:
|
||||
nullify: paypal_permissions_token
|
||||
addons_users:
|
||||
delete:
|
||||
listed: 0
|
||||
|
|
Загрузка…
Ссылка в новой задаче