Fix #277 -- Embeddable shop (#622)

* Vendor vue.js

* Refactor item_group_by_category to support vouchers

* Widget: Show product list

* Widget: free prices

* Widget: pictures and loading indicator

* Widget: First iframe steps

* Widget: Do not rerender iframe

* Widget: Error handling

* Improve widget

* Widget: localization tech

* Fix invoice style

* Voucher attribute and waiting list

* Add some iframe chrome

* First step to namespaced carts

* More isolation steps

* More cart isolation things

* More cart isolation things

* Mobile stuff

* Show cart on checkout pages

* PayPal and Stripe support

* Enable downloads

* Locale handling

* change text "save URL to this exact page"

* Widget: voucher redemption

* Widget: CSS

* CSS: Responsive

* Widget: CSS improvements

* Widget: Add embedding code generator

* Widget: Error messages and SSL check

* First tests

* Widget: tests

* Don't use IDs in widgets

* Widget: static files caching
This commit is contained in:
Raphael Michel
2017-10-28 21:54:27 +02:00
committed by GitHub
parent df7fbe5a66
commit 9767243a6d
56 changed files with 12819 additions and 317 deletions

View File

@@ -1,10 +1,12 @@
import json
import logging
import urllib.parse
from collections import OrderedDict
import paypalrestsdk
from django import forms
from django.contrib import messages
from django.core import signing
from django.template.loader import get_template
from django.utils.translation import ugettext as __, ugettext_lazy as _
@@ -89,14 +91,18 @@ class Paypal(BasePaymentProvider):
def checkout_prepare(self, request, cart):
self.init_api()
kwargs = {}
if request.resolver_match and 'cart_namespace' in request.resolver_match.kwargs:
kwargs['cart_namespace'] = request.resolver_match.kwargs['cart_namespace']
payment = paypalrestsdk.Payment({
'intent': 'sale',
'payer': {
"payment_method": "paypal",
},
"redirect_urls": {
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return'),
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort'),
"return_url": build_absolute_uri(request.event, 'plugins:paypal:return', kwargs=kwargs),
"cancel_url": build_absolute_uri(request.event, 'plugins:paypal:abort', kwargs=kwargs),
},
"transactions": [
{
@@ -131,7 +137,14 @@ class Paypal(BasePaymentProvider):
request.session['payment_paypal_id'] = payment.id
for link in payment.links:
if link.method == "REDIRECT" and link.rel == "approval_url":
return str(link.href)
if request.session.get('iframe_session', False):
signer = signing.Signer(salt='safe-redirect')
return (
build_absolute_uri(request.event, 'plugins:paypal:redirect') + '?url=' +
urllib.parse.quote(signer.sign(link.href))
)
else:
return str(link.href)
else:
messages.error(request, _('We had trouble communicating with PayPal'))
logger.error('Error on creating payment: ' + str(payment.error))

View File

@@ -0,0 +1,32 @@
{% load compress %}
{% load i18n %}
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{{ settings.PRETIX_INSTANCE_NAME }}</title>
{% compress css %}
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixbase/scss/cachedfiles.scss" %}"/>
{% endcompress %}
{% compress js %}
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>
{% endcompress %}
</head>
<body>
<div class="container">
<h1>{% trans "The payment process has started in a new window." %}</h1>
<p>
{% trans "The window to enter your payment data was not opened or was closed?" %}
</p>
<p>
<a href="{{ url }}" target="_blank">
{% trans "Click here in order to open the window." %}
</a>
</p>
<script>
window.open('{{ url|escapejs }}');
</script>
</div>
</body>
</html>

View File

@@ -2,12 +2,17 @@ from django.conf.urls import include, url
from pretix.multidomain import event_url
from .views import abort, refund, success, webhook
from .views import abort, redirect_view, refund, success, webhook
event_patterns = [
url(r'^paypal/', include([
url(r'^abort/$', abort, name='abort'),
url(r'^return/$', success, name='return'),
url(r'^redirect/$', redirect_view, name='redirect'),
url(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/abort/', abort, name='abort'),
url(r'w/(?P<cart_namespace>[a-zA-Z0-9]{16})/return/', success, name='return'),
event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
])),
]

View File

@@ -3,11 +3,13 @@ import logging
import paypalrestsdk
from django.contrib import messages
from django.core import signing
from django.db import transaction
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
@@ -17,12 +19,25 @@ from pretix.control.permissions import event_permission_required
from pretix.multidomain.urlreverse import eventreverse
from pretix.plugins.paypal.payment import Paypal
from pretix.plugins.stripe.models import ReferencedStripeObject
from pretix.presale.utils import event_view
logger = logging.getLogger('pretix.plugins.paypal')
@event_view(require_live=False)
@xframe_options_exempt
def redirect_view(request, *args, **kwargs):
signer = signing.Signer(salt='safe-redirect')
try:
url = signer.unsign(request.GET.get('url', ''))
except signing.BadSignature:
return HttpResponseBadRequest('Invalid parameter')
r = render(request, 'pretixplugins/paypal/redirect.html', {
'url': url,
})
r._csp_ignore = True
return r
def success(request, *args, **kwargs):
pid = request.GET.get('paymentId')
token = request.GET.get('token')
@@ -30,6 +45,10 @@ def success(request, *args, **kwargs):
request.session['payment_paypal_token'] = token
request.session['payment_paypal_payer'] = payer
urlkwargs = {}
if 'cart_namespace' in kwargs:
urlkwargs['cart_namespace'] = kwargs['cart_namespace']
if request.session.get('payment_paypal_order'):
order = Order.objects.get(pk=request.session.get('payment_paypal_order'))
else:
@@ -44,7 +63,8 @@ def success(request, *args, **kwargs):
else:
messages.error(request, _('Invalid response from PayPal received.'))
logger.error('Session did not contain payment_paypal_id')
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs={'step': 'payment'}))
urlkwargs['step'] = 'payment'
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs=urlkwargs))
if order:
return redirect(eventreverse(request.event, 'presale:event.order', kwargs={
@@ -52,7 +72,8 @@ def success(request, *args, **kwargs):
'secret': order.secret
}) + ('?paid=yes' if order.status == Order.STATUS_PAID else ''))
else:
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs={'step': 'confirm'}))
urlkwargs['step'] = 'confirm'
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs=urlkwargs))
def abort(request, *args, **kwargs):