|
|
|
from datetime import timedelta
|
|
|
|
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, Http404
|
|
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.contrib import messages
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
|
|
|
from .forms import NewPaymentForm
|
|
|
|
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS, Feedback
|
|
|
|
|
|
|
|
|
|
|
|
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':
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
if Payment.objects.filter(user=request.user, status='new').count() > 10:
|
|
|
|
messages.error(request, "Too many open payments.")
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
form = NewPaymentForm(request.POST)
|
|
|
|
|
|
|
|
if not form.is_valid():
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
if request.user.vpnuser.get_subscription() is not None:
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
subscr = form.cleaned_data['subscr'] == '1'
|
|
|
|
backend_id = form.cleaned_data['method']
|
|
|
|
months = int(form.cleaned_data['time'])
|
|
|
|
|
|
|
|
if backend_id not in ACTIVE_BACKENDS:
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
|
|
|
if subscr:
|
|
|
|
if months not in (3, 6, 12):
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
rps = Subscription(
|
|
|
|
user=request.user,
|
|
|
|
backend_id=backend_id,
|
|
|
|
period=str(months) + 'm',
|
|
|
|
)
|
|
|
|
rps.save()
|
|
|
|
|
|
|
|
r = rps.backend.new_subscription(rps)
|
|
|
|
|
|
|
|
else:
|
|
|
|
payment = Payment.create_payment(backend_id, request.user, months)
|
|
|
|
payment.save()
|
|
|
|
|
|
|
|
r = payment.backend.new_payment(payment)
|
|
|
|
|
|
|
|
if not r:
|
|
|
|
payment.status = 'error'
|
|
|
|
payment.save()
|
|
|
|
raise Exception("Failed to initialize payment #%d" % payment.id)
|
|
|
|
|
|
|
|
if isinstance(r, str):
|
|
|
|
return render(request, 'payments/form.html', dict(html=r))
|
|
|
|
elif r is None:
|
|
|
|
return redirect('payments:view', payment.id)
|
|
|
|
|
|
|
|
return r
|
|
|
|
|
|
|
|
def plain_callback(backend_name, method='callback'):
|
|
|
|
@csrf_exempt
|
|
|
|
def callback(request):
|
|
|
|
backend = require_backend(backend_name)
|
|
|
|
|
|
|
|
m = getattr(backend, method)
|
|
|
|
if m and m(Payment, request):
|
|
|
|
return HttpResponse()
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
return callback
|
|
|
|
|
|
|
|
def payment_callback(backend_name):
|
|
|
|
@csrf_exempt
|
|
|
|
def callback(request, id):
|
|
|
|
backend = require_backend(backend_name)
|
|
|
|
p = Payment.objects.get(id=id)
|
|
|
|
|
|
|
|
if backend.callback(p, request):
|
|
|
|
return HttpResponse()
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
return callback
|
|
|
|
|
|
|
|
def sub_callback(backend_name):
|
|
|
|
@csrf_exempt
|
|
|
|
def callback(request, id):
|
|
|
|
backend = require_backend(backend_name)
|
|
|
|
|
|
|
|
p = Subscription.objects.get(id=id)
|
|
|
|
|
|
|
|
if backend.callback_subscr(p, request):
|
|
|
|
return HttpResponse()
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
return callback
|
|
|
|
|
|
|
|
@csrf_exempt
|
|
|
|
def stripe_hook(request):
|
|
|
|
backend = require_backend('stripe')
|
|
|
|
|
|
|
|
if backend.webhook(request):
|
|
|
|
return HttpResponse()
|
|
|
|
else:
|
|
|
|
return HttpResponseBadRequest()
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@csrf_exempt
|
|
|
|
def view(request, id):
|
|
|
|
p = Payment.objects.get(id=id, user=request.user)
|
|
|
|
return render(request, 'payments/view.html', dict(payment=p))
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def cancel(request, id):
|
|
|
|
p = Payment.objects.get(id=id, user=request.user)
|
|
|
|
if p.status == 'new':
|
|
|
|
p.status = 'cancelled'
|
|
|
|
p.save()
|
|
|
|
return render(request, 'payments/view.html', dict(payment=p))
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def cancel_subscr(request, id=None):
|
|
|
|
if request.method == 'POST' and id:
|
|
|
|
p = Subscription.objects.get(id=id, user=request.user)
|
|
|
|
|
|
|
|
# Saving any feedback note
|
|
|
|
feedback = request.POST.get('feedback')
|
|
|
|
if feedback:
|
|
|
|
feedback = feedback[:10000]
|
|
|
|
f = Feedback(user=request.user, subscription=p, message=feedback)
|
|
|
|
f.save()
|
|
|
|
|
|
|
|
try:
|
|
|
|
if p.backend.cancel_subscription(p):
|
|
|
|
messages.add_message(request, messages.INFO, _("Subscription cancelled!"))
|
|
|
|
else:
|
|
|
|
messages.add_message(request, messages.ERROR, _("Could not cancel the subscription. It may have already been cancelled or caused an error."))
|
|
|
|
except NotImplementedError:
|
|
|
|
pass
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
subscription = request.user.vpnuser.get_subscription(include_unconfirmed=True)
|
|
|
|
return render(request, 'payments/cancel_subscr.html', {
|
|
|
|
'subscription': subscription,
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def return_subscr(request, id):
|
|
|
|
p = Subscription.objects.get(id=id, user=request.user)
|
|
|
|
if p.status == 'new':
|
|
|
|
p.status = 'unconfirmed'
|
|
|
|
p.save()
|
|
|
|
return redirect('account:index')
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def list_payments(request):
|
|
|
|
# Only show recent cancelled payments
|
|
|
|
cancelled_limit = timezone.now() - timedelta(days=3)
|
|
|
|
|
|
|
|
objects = request.user.payment_set.exclude(status='cancelled',
|
|
|
|
created__lte=cancelled_limit)
|
|
|
|
return render(request, 'payments/list.html', dict(payments=objects))
|