Big payments update

master
Alice 5 years ago
parent 4b056c8ad0
commit acf34a2ac9

@ -218,26 +218,36 @@ VPN_AUTH_STORAGE = 'inst'
# Payment backends. See payments/backends.py for more infos.
PAYMENTS_BACKENDS = {
'bitcoin': {
'enabled': False,
'url': 'http://test:test@127.0.0.1:18332/',
# 'chain': '', # mainnet, testnet, regnet
},
'paypal': {
'TEST': True, # Sandbox
'ADDRESS': 'paypal@ccrypto.org', # Your PayPal primary address
'enabled': False,
'test': True, # Sandbox
# 'api_base': '',
'address': '', # PayPal address to send to
# 'receiver': '', # PayPal primary address if different
# 'currency': 'EUR',
# 'header_image': '',
},
# Remove the leading '_' to enable these backends.
'_stripe': {
'API_KEY': '',
'PUBLIC_KEY': '',
'stripe': {
'enabled': False,
'secret_key': '',
'public_key': '',
'currency': 'EUR',
# 'title': '',
# 'header_image': '',
},
'_bitcoin': {
'URL': 'http://test:test@127.0.0.1:18332/',
'BITCOIN_VALUE': 36000, # Value of one bitcoin in currency*100
'coingate': {
'enabled': False,
# 'sandbox': True,
# 'api_base': '',
'api_token': '',
'currency': 'EUR',
# 'title': '',
},
'_coingate': {
# 'SANDBOX': True,
# 'API_BASE': '',
'API_TOKEN': '',
'CURRENCY': '',
'TITLE': '',
}
}
PAYMENTS_CURRENCY = ('eur', '')

@ -1,5 +1,7 @@
import json
from django.shortcuts import resolve_url
from django.contrib import admin
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _
from .models import Payment, Subscription
@ -9,6 +11,18 @@ def subscr_mark_as_cancelled(modeladmin, request, queryset):
subscr_mark_as_cancelled.short_description = _("Mark as cancelled (do not actually cancel)")
def link(text, url):
if not url:
return text
if not text:
text = url
return format_html('<a href="{}">{}</a>', url, text)
def json_format(code):
j = json.dumps(code, indent=2)
return format_html("<pre>{}</pre>", j)
class PaymentAdmin(admin.ModelAdmin):
model = Payment
list_display = ('user', 'backend', 'status', 'amount', 'paid_amount', 'created')
@ -21,24 +35,24 @@ class PaymentAdmin(admin.ModelAdmin):
}),
(_("Payment Data"), {
'fields': ('amount_fmt', 'paid_amount_fmt',
'backend_extid_link', 'backend_data'),
'backend_extid_link', 'backend_data_fmt'),
}),
)
readonly_fields = ('backend', 'user_link', 'time', 'status', 'status_message',
'amount_fmt', 'paid_amount_fmt', 'subscription_link',
'backend_extid_link', 'backend_data')
'backend_extid_link', 'backend_data_fmt')
search_fields = ('user__username', 'user__email', 'backend_extid', 'backend_data')
def backend(self, object):
return object.backend.backend_verbose_name
def backend_data_fmt(self, object):
return json_format(object.backend_data)
def backend_extid_link(self, object):
ext_url = object.backend.get_ext_url(object)
if ext_url:
return '<a href="%s">%s</a>' % (ext_url, object.backend_extid)
return object.backend_extid
backend_extid_link.allow_tags = True
return link(object.backend_extid, ext_url)
def amount_fmt(self, object):
return '%.2f %s' % (object.amount / 100, object.currency_name)
@ -50,24 +64,23 @@ class PaymentAdmin(admin.ModelAdmin):
def user_link(self, object):
change_url = resolve_url('admin:auth_user_change', object.user.id)
return '<a href="%s">%s</a>' % (change_url, object.user.username)
user_link.allow_tags = True
return link(object.user.username, change_url)
user_link.short_description = 'User'
def subscription_link(self, object):
change_url = resolve_url('admin:payments_subscription_change',
object.subscription.id)
return '<a href="%s">%s</a>' % (change_url, object.subscription.id)
subscription_link.allow_tags = True
return link(object.subscription.id, change_url)
subscription_link.short_description = 'Subscription'
class SubscriptionAdmin(admin.ModelAdmin):
model = Subscription
list_display = ('user', 'created', 'status', 'backend', 'backend_extid')
list_filter = ('backend_id', 'status')
readonly_fields = ('user_link', 'backend', 'period', 'created', 'status',
'last_confirmed_payment', 'payments_links',
'backend_extid_link', 'backend_data')
'backend_extid_link', 'backend_data_fmt')
search_fields = ('user__username', 'user__email', 'backend_extid', 'backend_data')
actions = (subscr_mark_as_cancelled,)
fieldsets = (
@ -76,32 +89,31 @@ class SubscriptionAdmin(admin.ModelAdmin):
'last_confirmed_payment'),
}),
(_("Payment Data"), {
'fields': ('backend_extid_link', 'backend_data'),
'fields': ('backend_extid_link', 'backend_data_fmt'),
}),
)
def backend(self, object):
return object.backend.backend_verbose_name
def backend_data_fmt(self, object):
return json_format(object.backend_data)
def user_link(self, object):
change_url = resolve_url('admin:auth_user_change', object.user.id)
return '<a href="%s">%s</a>' % (change_url, object.user.username)
user_link.allow_tags = True
return link(object.user.id, change_url)
user_link.short_description = 'User'
def payments_links(self, object):
fmt = '<a href="%s?subscription__id__exact=%d">%d payments</a>'
payments_url = resolve_url('admin:payments_payment_changelist')
count = Payment.objects.filter(subscription=object).count()
return fmt % (payments_url, object.id, count)
payments_links.allow_tags = True
payments_url = resolve_url('admin:payments_payment_changelist')
url = "%s?subscription__id__exact=%s" % (payments_url, object.id)
return link("%d payment(s)" % count, url)
payments_links.short_description = 'Payments'
def backend_extid_link(self, object):
ext_url = object.backend.get_subscr_ext_url(object)
if ext_url:
return '<a href="%s">%s</a>' % (ext_url, object.backend_extid)
return object.backend_extid
return link(object.backend_extid, ext_url)
backend_extid_link.allow_tags = True
admin.site.register(Payment, PaymentAdmin)

@ -22,13 +22,13 @@ class BitcoinBackend(BackendBase):
from bitcoin import SelectParams
from bitcoin.rpc import Proxy
self.account = settings.get('ACCOUNT', 'ccvpn3')
self.account = settings.get('account', 'ccvpn3')
chain = settings.get('CHAIN')
chain = settings.get('chain')
if chain:
SelectParams(chain)
self.url = settings.get('URL')
self.url = settings.get('url')
if not self.url:
return

@ -26,18 +26,20 @@ class CoinGateBackend(BackendBase):
backend_has_recurring = False
def __init__(self, settings):
self.api_token = settings.get('API_TOKEN')
self.api_token = settings.get('api_token')
if not self.api_token:
return
self.currency = settings.get('CURRENCY', 'EUR')
self.title = settings.get('TITLE', 'VPN Payment')
self.currency = settings.get('currency', 'EUR')
self.title = settings.get('title', 'VPN Payment')
if settings.get('SANDBOX'):
if settings.get('sandbox'):
self.sandbox = True
self.api_base = "https://api-sandbox.coingate.com"
else:
self.sandbox = False
default_base = "https://api.coingate.com"
self.api_base = settings.get('API_BASE', default_base)
self.api_base = settings.get('api_base', default_base)
self.backend_enabled = True
@ -71,6 +73,7 @@ class CoinGateBackend(BackendBase):
url = order['payment_url']
payment.backend_extid = order['id']
payment.backend_data['coingate_id'] = order['id']
payment.backend_data['coingate_url'] = url
payment.backend_data['coingate_token'] = token
@ -126,6 +129,9 @@ class CoinGateBackend(BackendBase):
def get_ext_url(self, payment):
if not payment.backend_extid:
return None
return 'https://dashboard.stripe.com/payments/%s' % payment.backend_extid
if self.sandbox:
return 'https://sandbox.coingate.com/account/orders/%s' % payment.backend_extid
else:
return 'https://coingate.com/account/orders/%s' % payment.backend_extid

@ -15,18 +15,18 @@ class PaypalBackend(BackendBase):
backend_has_recurring = True
def __init__(self, settings):
self.test = settings.get('TEST', False)
self.header_image = settings.get('HEADER_IMAGE', None)
self.title = settings.get('TITLE', 'VPN Payment')
self.currency = settings.get('CURRENCY', 'EUR')
self.account_address = settings.get('ADDRESS')
self.receiver_address = settings.get('RECEIVER', self.account_address)
self.test = settings.get('test', False)
self.header_image = settings.get('header_image', None)
self.title = settings.get('title', 'VPN Payment')
self.currency = settings.get('currency', 'EUR')
self.account_address = settings.get('address')
self.receiver_address = settings.get('receiver', self.account_address)
if self.test:
default_api = 'https://www.sandbox.paypal.com/'
else:
default_api = 'https://www.paypal.com/'
self.api_base = settings.get('API_BASE', default_api)
self.api_base = settings.get('api_base', default_api)
if self.account_address:
self.backend_enabled = True

@ -1,7 +1,6 @@
import json
from django.utils.translation import ugettext_lazy as _
from django.urls import reverse
from django.conf import settings as project_settings
from .base import BackendBase
@ -16,133 +15,154 @@ class StripeBackend(BackendBase):
return 'ccvpn_' + period
def __init__(self, settings):
if 'API_KEY' not in settings or 'PUBLIC_KEY' not in settings:
return
self.public_key = settings.get('public_key')
self.secret_key = settings.get('secret_key')
self.wh_key = settings.get('wh_key')
if not self.public_key or not self.secret_key or not self.wh_key:
raise Exception("Missing keys for stripe backend")
import stripe
self.stripe = stripe
stripe.api_key = self.secret_key
stripe.api_key = settings['API_KEY']
self.pubkey = settings['PUBLIC_KEY']
self.header_image = settings.get('HEADER_IMAGE', '')
self.currency = settings.get('CURRENCY', 'EUR')
self.name = settings.get('NAME', 'VPN Payment')
self.header_image = settings.get('header_image', '')
self.currency = settings.get('currency', 'EUR')
self.title = settings.get('title', 'VPN Payment')
self.backend_enabled = True
def make_redirect(self, session):
return '''
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
document.write("<p>Redirecting to the payment page...</p>");
var stripe = Stripe("{pk}");
stripe.redirectToCheckout({{
sessionId: "{sess}"
}});
</script>
<noscript><p>Please enable JavaScript to use the payment form.</p></noscript>
'''.format(pk=self.public_key, sess=session['id'])
def new_payment(self, payment):
desc = str(payment.time) + ' for ' + payment.user.username
form = '''
<form action="{post}" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{pubkey}"
data-image="{img}"
data-name="{name}"
data-currency="{curr}"
data-description="{desc}"
data-amount="{amount}"
data-email="{email}"
data-locale="auto"
data-zip-code="true"
data-alipay="true">
</script>
</form>
'''
return form.format(
post=reverse('payments:cb_stripe', args=(payment.id,)),
pubkey=self.pubkey,
img=self.header_image,
email=payment.user.email or '',
name=self.name,
desc=desc,
amount=payment.amount,
curr=self.currency,
root_url = project_settings.ROOT_URL
assert root_url
months = payment.time.days // 30
if months > 1:
desc = '{} months for {}'.format(months, payment.user.username)
else:
desc = 'One month for {}'.format(payment.user.username)
session = self.stripe.checkout.Session.create(
success_url=root_url + reverse('payments:view', args=(payment.id,)),
cancel_url=root_url + reverse('payments:cancel', args=(payment.id,)),
payment_method_types=['card'],
line_items=[
{
'amount': payment.amount,
'currency': self.currency.lower(),
'name': self.title,
'description': desc,
'quantity': 1,
}
],
)
payment.backend_extid = session['id']
payment.backend_data = {'session_id': session['id']}
payment.save()
return self.make_redirect(session)
def new_subscription(self, subscr):
desc = 'Subscription (' + str(subscr.period) + ') for ' + subscr.user.username
form = '''
<form action="{post}" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{pubkey}"
data-image="{img}"
data-name="{name}"
data-currency="{curr}"
data-description="{desc}"
data-amount="{amount}"
data-email="{email}"
data-locale="auto"
data-zip-code="true"
data-alipay="true">
</script>
</form>
<noscript><p>Please enable JavaScript to use the payment form.</p></noscript>
'''
return form.format(
post=reverse('payments:cb_stripe_subscr', args=(subscr.id,)),
pubkey=self.pubkey,
img=self.header_image,
email=subscr.user.email or '',
name=self.name,
desc=desc,
amount=subscr.period_amount,
curr=self.currency,
root_url = project_settings.ROOT_URL
assert root_url
session = self.stripe.checkout.Session.create(
success_url=root_url + reverse('payments:return_subscr', args=(subscr.id,)),
cancel_url=root_url + reverse('payments:cancel_subscr', args=(subscr.id,)),
client_reference_id='sub_%d'%subscr.id,
payment_method_types=['card'],
subscription_data={
'items': [{
'plan': self.get_plan_id(subscr.period),
'quantity': 1,
}],
},
)
subscr.backend_data = {'session_id': session['id']}
subscr.save()
return self.make_redirect(session)
def cancel_subscription(self, subscr):
if subscr.status not in ('new', 'unconfirmed', 'active'):
return
try:
cust = self.stripe.Customer.retrieve(subscr.backend_extid)
except self.stripe.error.InvalidRequestError:
return
try:
# Delete customer and cancel any active subscription
cust.delete()
except self.stripe.error.InvalidRequestError:
if subscr.backend_extid.startswith('pi'):
# a session that didn't create a subscription yet (intent)
pass
elif subscr.backend_extid.startswith('sub_'):
# Subscription object
try:
self.stripe.Subscription.delete(subscr.backend_extid)
except self.stripe.error.InvalidRequestError:
pass
elif subscr.backend_extid.startswith('cus_'):
# Legacy Customer object
try:
cust = self.stripe.Customer.retrieve(subscr.backend_extid)
except self.stripe.error.InvalidRequestError:
return
try:
# Delete customer and cancel any active subscription
cust.delete()
except self.stripe.error.InvalidRequestError:
pass
else:
raise Exception("Failed to cancel subscription %r" % subscr.backend_extid)
subscr.status = 'cancelled'
subscr.save()
def callback(self, payment, request):
post_data = request.POST
def webhook_session_completed(self, event):
session = event['data']['object']
token = post_data.get('stripeToken')
if not token:
payment.status = 'cancelled'
payment.status_message = _("No payment information was received.")
return
if session['subscription']:
# Subscription creation
from payments.models import Payment, Subscription
months = int(payment.time.days / 30)
username = payment.user.username
sub_id = session['subscription']
assert sub_id
try:
charge = self.stripe.Charge.create(
amount=payment.amount,
currency=self.currency,
card=token,
description="%d months for %s" % (months, username),
)
payment.backend_extid = charge['id']
parts = session['client_reference_id'].split('_')
if len(parts) != 2 or parts[0] != 'sub':
raise Exception("invalid reference id")
sub_internal_id = int(parts[1])
if charge['refunded'] or not charge['paid']:
payment.status = 'rejected'
payment.status_message = _("The payment has been refunded or rejected.")
payment.save()
return
# Fetch sub by ID and confirm it
subscr = Subscription.objects.get(id=sub_internal_id)
subscr.status = 'active'
subscr.backend_extid = sub_id
subscr.backend_data['subscription_id'] = sub_id
subscr.save()
payment.paid_amount = int(charge['amount'])
payment = subscr.create_payment()
payment.status = 'confirmed'
payment.paid_amount = payment.amount
payment.backend_extid = None
payment.save()
if payment.paid_amount < payment.amount:
payment.status = 'error'
payment.status_message = _("The paid amount is under the required amount.")
payment.save()
return
payment.user.vpnuser.add_paid_time(payment.time)
payment.user.vpnuser.on_payment_confirmed(payment)
payment.user.vpnuser.save()
payment.save()
else:
from payments.models import Payment
payment = Payment.objects.filter(backend_extid=session['id']).get()
# the amount is provided server-side, we do not have to check
payment.paid_amount = payment.amount
payment.status = 'confirmed'
payment.status_message = None
@ -151,54 +171,47 @@ class StripeBackend(BackendBase):
payment.user.vpnuser.on_payment_confirmed(payment)
payment.user.vpnuser.save()
except self.stripe.error.CardError as e:
payment.status = 'rejected'
payment.status_message = e.json_body['error']['message']
payment.save()
def get_subscription_from_invoice(self, invoice):
from payments.models import Subscription
def callback_subscr(self, subscr, request):
post_data = request.POST
token = post_data.get('stripeToken')
if not token:
subscr.status = 'cancelled'
subscr.save()
return
subscription_id = invoice['subscription']
customer_id = invoice['customer']
try:
cust = self.stripe.Customer.create(
source=token,
plan=self.get_plan_id(subscr.period),
)
except self.stripe.error.InvalidRequestError:
return
except self.stripe.CardError as e:
subscr.status = 'error'
subscr.backend_data['stripe_error'] = e.json_body['error']['message']
return
# once it's confirmed, the id to the subscription is stored as extid
subscr = Subscription.objects.filter(backend_extid=subscription_id).first()
if subscr:
return subscr
# We don't know much about the new Payment, but we know it
# succeeded. Wekhooks aren't very reliable, so let's mark it as active
# anyway.
subscr.status = 'active'
subscr.backend_extid = cust['id']
subscr.save()
# older subscriptions will have a customer id instead
subscr = Subscription.objects.filter(backend_extid=customer_id).first()
if subscr:
return subscr
return None
def webhook_payment_succeeded(self, event):
from payments.models import Subscription, Payment
""" webhook event for a subscription's succeeded payment """
from payments.models import Payment
invoice = event['data']['object']
customer_id = invoice['customer']
subscr = self.get_subscription_from_invoice(invoice)
if not subscr:
# the subscription does not exist
# checkout.confirmed event will create it and handle the initial payment
return True
# raise Exception("Unknown subscription for invoice %r" % invoice['id'])
# Prevent making duplicate Payments if event is received twice
pc = Payment.objects.filter(backend_extid=invoice['id']).count()
if pc > 0:
return
subscr = Subscription.objects.get(backend_extid=customer_id)
payment = subscr.create_payment()
payment.status = 'confirmed'
payment.paid_amount = invoice['total']
payment.paid_amount = payment.amount
payment.backend_extid = invoice['id']
if invoice['subscription']:
payment.backend_sub_id = invoice['subscription']['id']
payment.backend_data = {'event_id': event['id']}
payment.save()
@ -207,26 +220,51 @@ class StripeBackend(BackendBase):
payment.user.vpnuser.save()
payment.save()
subscr.status = 'active'
subscr.save()
def webhook(self, request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
try:
event_json = json.loads(request.body.decode('utf-8'))
event = self.stripe.Event.retrieve(event_json["id"])
except (ValueError, self.stripe.error.InvalidRequestError):
event = self.stripe.Webhook.construct_event(
payload, sig_header, self.wh_key,
)
except (ValueError, self.stripe.error.InvalidRequestError, self.stripe.error.SignatureVerificationError):
return False
if event['type'] == 'invoice.payment_succeeded':
self.webhook_payment_succeeded(event)
if event['type'] == 'checkout.session.completed':
self.webhook_session_completed(event)
return True
def get_ext_url(self, payment):
if not payment.backend_extid:
extid = payment.backend_extid
if not extid:
return None
return 'https://dashboard.stripe.com/payments/%s' % payment.backend_extid
if extid.startswith('in_'):
return 'https://dashboard.stripe.com/invoices/%s' % extid
if extid.startswith('ch_'):
return 'https://dashboard.stripe.com/payments/%s' % extid
def get_subscr_ext_url(self, subscr):
if not subscr.backend_extid:
extid = subscr.backend_extid
if not extid:
return None
return 'https://dashboard.stripe.com/customers/%s' % subscr.backend_extid
if extid.startswith('sub_') and self.stripe:
livemode = False
try:
sub = self.stripe.Subscription.retrieve(extid)
livemode = sub['livemode']
except Exception:
pass
if livemode:
return 'https://dashboard.stripe.com/subscriptions/' + extid
else:
return 'https://dashboard.stripe.com/test/subscriptions/' + extid
if extid.startswith('cus_'):
return 'https://dashboard.stripe.com/customers/%s' % subscr.backend_extid

@ -1,3 +1,4 @@
import logging
from django.db import models
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
@ -7,6 +8,8 @@ from datetime import timedelta
from ccvpn.common import get_price
from .backends import BackendBase
logger = logging.getLogger(__name__)
backends_settings = settings.PAYMENTS_BACKENDS
assert isinstance(backends_settings, dict)
@ -39,6 +42,8 @@ SUBSCR_PERIOD_CHOICES = (
('12m', _("Every year")),
)
BACKEND_CLASSES = BackendBase.__subclasses__()
# All known backends (classes)
BACKENDS = {}
BACKEND_CHOICES = []
@ -47,11 +52,14 @@ BACKEND_CHOICES = []
ACTIVE_BACKENDS = {}
ACTIVE_BACKEND_CHOICES = []
for cls in BackendBase.__subclasses__():
logger.info("loading payment backends...")
for cls in BACKEND_CLASSES:
name = cls.backend_id
prefix = "Backend {:<8}:".format(name)
assert isinstance(name, str)
if name not in backends_settings:
logger.info("%s ☒ disabled (no settings)", prefix)
continue
backend_settings = backends_settings.get(name, {})
@ -59,10 +67,11 @@ for cls in BackendBase.__subclasses__():
if hasattr(v, '__call__'):
backend_settings[k] = v()
if not backend_settings.get('enabled'):
logger.info("%s ☒ disabled (by settings)", prefix)
continue
obj = cls(backend_settings)
if not obj.backend_enabled:
if name in backends_settings:
raise Exception("Invalid settings for payment backend %r" % name)
BACKENDS[name] = obj
BACKEND_CHOICES.append((name, cls.backend_verbose_name))
@ -70,10 +79,15 @@ for cls in BackendBase.__subclasses__():
if obj.backend_enabled:
ACTIVE_BACKENDS[name] = obj
ACTIVE_BACKEND_CHOICES.append((name, cls.backend_verbose_name))
logger.info("%s ☑ initialized", prefix)
else:
logger.info("%s ☒ disabled (initialization failed)", prefix)
BACKEND_CHOICES = sorted(BACKEND_CHOICES, key=lambda x: x[0])
ACTIVE_BACKEND_CHOICES = sorted(ACTIVE_BACKEND_CHOICES, key=lambda x: x[0])
logger.info("finished. %d/%d backends active", len(ACTIVE_BACKENDS), len(BACKEND_CLASSES))
def period_months(p):
return {

@ -13,9 +13,9 @@ class CoinGateBackendTest(TestCase):
self.user = User.objects.create_user('test', 'test_user@example.com', None)
self.backend_settings = dict(
API_TOKEN='test',
TITLE='Test Title',
CURRENCY='EUR',
api_token='test',
title='Test Title',
currency='EUR',
)
def test_payment(self):

@ -143,10 +143,10 @@ class PaypalBackendTest(TestCase):
)
settings = dict(
TEST=True,
TITLE='Test Title',
CURRENCY='EUR',
ADDRESS='test_business@example.com',
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):
@ -196,10 +196,10 @@ class PaypalBackendTest(TestCase):
)
settings = dict(
TEST=True,
TITLE='Test Title',
CURRENCY='EUR',
ADDRESS='test_business@example.com',
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):
@ -235,10 +235,10 @@ class PaypalBackendTest(TestCase):
)
settings = dict(
TEST=True,
TITLE='Test Title',
CURRENCY='EUR',
ADDRESS='test_business@example.com',
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):

@ -20,10 +20,11 @@ class StripeBackendTest(TestCase):
)
settings = dict(
API_KEY='test_secret_key',
PUBLIC_KEY='test_public_key',
CURRENCY='EUR',
NAME='Test Name',
secret_key='test_secret_key',
public_key='test_public_key',
wh_key='test_wh_key',
currency='EUR',
name='Test Name',
)
with self.settings(ROOT_URL='root'):

@ -3,7 +3,7 @@ from django.shortcuts import render, redirect
from django.urls import reverse
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotFound, Http404
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.contrib import messages
@ -13,6 +13,15 @@ from .forms import NewPaymentForm
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS
def require_backend(name):
backend = BACKENDS.get(name)
if not backend:
raise Http404()
if not backend.backend_enabled:
raise Http404()
return backend
@login_required
def new(request):
if request.method != 'POST':
@ -68,11 +77,10 @@ def new(request):
@csrf_exempt
def callback_paypal(request, id):
""" PayPal IPN """
if not BACKENDS['paypal'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('paypal')
p = Payment.objects.get(id=id)
if BACKENDS['paypal'].callback(p, request):
if backend.callback(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@ -82,22 +90,20 @@ def callback_paypal(request, id):
@login_required
def callback_stripe(request, id):
""" Stripe button POST """
if not BACKENDS['stripe'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('stripe')
p = Payment.objects.get(id=id)
BACKENDS['stripe'].callback(p, request)
backend.callback(p, request)
return redirect(reverse('payments:view', args=(id,)))
@csrf_exempt
def callback_coingate(request, id):
""" CoinGate payment callback """
if not BACKENDS['coingate'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('coingate')
p = Payment.objects.get(id=id)
if BACKENDS['coingate'].callback(p, request):
if backend.callback(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@ -105,10 +111,9 @@ def callback_coingate(request, id):
@csrf_exempt
def callback_coinbase(request):
if not BACKENDS['coinbase'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('coinbase')
if BACKENDS['coinbase'].callback(Payment, request):
if backend.callback(Payment, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@ -117,11 +122,10 @@ def callback_coinbase(request):
@csrf_exempt
def callback_paypal_subscr(request, id):
""" PayPal Subscription IPN """
if not BACKENDS['paypal'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('paypal')
p = Subscription.objects.get(id=id)
if BACKENDS['paypal'].callback_subscr(p, request):
if paypal.callback_subscr(p, request):
return HttpResponse()
else:
return HttpResponseBadRequest()
@ -131,11 +135,10 @@ def callback_paypal_subscr(request, id):
@login_required
def callback_stripe_subscr(request, id):
""" Stripe subscription form target """
if not BACKENDS['stripe'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('stripe')
p = Subscription.objects.get(id=id)
BACKENDS['stripe'].callback_subscr(p, request)
backend.callback_subscr(p, request)
if p.status == 'error' or p.status == 'cancelled':
messages.add_message(request, messages.ERROR,
_("Error subscribing. It usually means you don't"
@ -147,10 +150,9 @@ def callback_stripe_subscr(request, id):
@csrf_exempt
def stripe_hook(request):
if not BACKENDS['stripe'].backend_enabled:
return HttpResponseNotFound()
backend = require_backend('stripe')
if BACKENDS['stripe'].webhook(request):
if backend.webhook(request):
return HttpResponse()
else:
return HttpResponseBadRequest()

Loading…
Cancel
Save