From 6a4a8af731664ba049fec22b5cc8d02dff52caca Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Sun, 2 Sep 2018 15:25:33 +0200 Subject: [PATCH] Improve cookie detection and handling --- .../pretixpresale/event/cookies.html | 38 +++++++++++++++++++ .../templates/pretixpresale/event/index.html | 23 ----------- .../pretixpresale/event/voucher.html | 5 ++- src/pretix/presale/views/cart.py | 14 ++++++- src/pretix/presale/views/event.py | 30 +++++++++++---- src/pretix/presale/views/waiting.py | 22 ++++++++++- src/pretix/static/pretixbase/scss/error.scss | 4 ++ .../static/pretixpresale/js/widget/widget.js | 14 +++++-- 8 files changed, 112 insertions(+), 38 deletions(-) create mode 100644 src/pretix/presale/templates/pretixpresale/event/cookies.html diff --git a/src/pretix/presale/templates/pretixpresale/event/cookies.html b/src/pretix/presale/templates/pretixpresale/event/cookies.html new file mode 100644 index 0000000000..da29c3a0c3 --- /dev/null +++ b/src/pretix/presale/templates/pretixpresale/event/cookies.html @@ -0,0 +1,38 @@ +{% extends "error.html" %} +{% load i18n %} +{% load eventurl %} + +{% block content %} + {% if cart_namespace %} +

{% trans "Please continue in a new tab" %}

+

+ {% blocktrans trimmed %} + Your browser is configured to block cookies from third-party website elements. Unfortunately, this + means we cannot show you this ticket shop embedded into the website. Please try to open the ticket + shop in a new tab or change your browser settings. + {% endblocktrans %} +

+

+ {% blocktrans trimmed %} + We apologize for the inconvenience! + {% endblocktrans %} +

+
+ + {% trans "Continue in new tab" %} + + +
+ {% else %} +

{% trans "Cookies not supported" %}

+
+ {% blocktrans trimmed %} + Your browser does not accept cookies from us. However, we need to set a cookie to remember who + you are and what is in your cart. Please change your browser settings accordingly. + {% endblocktrans %} +
+ {% endif %} +{% endblock %} diff --git a/src/pretix/presale/templates/pretixpresale/event/index.html b/src/pretix/presale/templates/pretixpresale/event/index.html index b2840e6b43..92e058c489 100644 --- a/src/pretix/presale/templates/pretixpresale/event/index.html +++ b/src/pretix/presale/templates/pretixpresale/event/index.html @@ -106,29 +106,6 @@ {% endif %} - {% if cookie_warning %} -
- {% if cart_namespace %} - {% blocktrans trimmed %} - Your browser does not accept cookies from us. However, we need to set a cookie to remember who - you are and what is in your cart. Please try to open the ticket shop in a new tab or change your - browser settings. - {% endblocktrans %} -
- - {% trans "Open ticket shop in new tab" %} - -
- {% else %} - {% blocktrans trimmed %} - Your browser does not accept cookies from us. However, we need to set a cookie to remember who - you are and what is in your cart. Please change your browser settings accordingly. - {% endblocktrans %} - {% endif %} -
- {% endif %} - {% if subevent or not event.has_subevents %} {% if not ev.presale_is_running %}
diff --git a/src/pretix/presale/templates/pretixpresale/event/voucher.html b/src/pretix/presale/templates/pretixpresale/event/voucher.html index 8123c4c3d0..ee273ad5ee 100644 --- a/src/pretix/presale/templates/pretixpresale/event/voucher.html +++ b/src/pretix/presale/templates/pretixpresale/event/voucher.html @@ -19,8 +19,9 @@ {% endblocktrans %}

{% if event.presale_is_running or event.settings.show_items_outside_presale_period %} -
+ {% csrf_token %} diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py index de5096d194..fc7c166bda 100644 --- a/src/pretix/presale/views/cart.py +++ b/src/pretix/presale/views/cart.py @@ -1,6 +1,7 @@ import mimetypes import os +from django.conf import settings from django.contrib import messages from django.db.models import Q from django.http import FileResponse, Http404, JsonResponse @@ -47,7 +48,7 @@ class CartActionMixin: u += '&require_cookie=true' else: u += '?require_cookie=true' - if 'iframe' in self.request.GET: + if 'iframe' in self.request.GET or settings.SESSION_COOKIE_NAME not in self.request.COOKIES: cart_id = get_or_create_cart_id(self.request) u += '&cart_id={}'.format(cart_id) return u @@ -383,6 +384,12 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, TemplateView): context['subevent'] = self.subevent + context['new_tab'] = ( + 'require_cookie' in self.request.GET and + settings.SESSION_COOKIE_NAME not in self.request.COOKIES + # Cookies are not supported! Lets just make the form open in a new tab + ) + return context def dispatch(self, request, *args, **kwargs): @@ -436,6 +443,11 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, TemplateView): return super().dispatch(request, *args, **kwargs) + def get(self, request, *args, **kwargs): + if 'iframe' in request.GET and 'require_cookie' not in request.GET: + return redirect(request.get_full_path() + '&require_cookie=1') + return super().get(request, *args, **kwargs) + @method_decorator(xframe_options_exempt, 'dispatch') class AnswerDownload(EventViewMixin, View): diff --git a/src/pretix/presale/views/event.py b/src/pretix/presale/views/event.py index d5e73e85a7..6e4250ff28 100644 --- a/src/pretix/presale/views/event.py +++ b/src/pretix/presale/views/event.py @@ -9,8 +9,7 @@ from django.conf import settings from django.core.exceptions import PermissionDenied from django.db.models import Count, Prefetch, Q from django.http import Http404, HttpResponse -from django.shortcuts import get_object_or_404, redirect -from django.urls import reverse +from django.shortcuts import get_object_or_404, redirect, render from django.utils.decorators import method_decorator from django.utils.timezone import now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ @@ -181,8 +180,28 @@ class EventIndex(EventViewMixin, CartMixin, TemplateView): self.subevent = None if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET: + # User has clicked "Open in a new tab" link in widget get_or_create_cart_id(request) - return redirect(reverse('presale:event.index', kwargs=kwargs)) + return redirect(eventreverse(request.event, 'presale:event.index', kwargs=kwargs)) + elif request.GET.get('iframe', '') == '1' and 'take_cart_id' in request.GET: + # Widget just opened, a cart already exists. Let's to a stupid redirect to check if cookies are disabled + get_or_create_cart_id(request) + return redirect(eventreverse(request.event, 'presale:event.index', kwargs=kwargs) + '?require_cookie=true&cart_id={}'.format( + request.GET.get('take_cart_id') + )) + elif 'require_cookie' in request.GET and settings.SESSION_COOKIE_NAME not in request.COOKIES: + # Cookies are in fact not supported + r = render(request, 'pretixpresale/event/cookies.html', { + 'url': eventreverse( + request.event, "presale:event.index", kwargs={'cart_namespace': kwargs.get('cart_namespace')} + ) + ( + "?src=widget&take_cart_id={}".format(request.GET.get('cart_id')) + if "cart_id" in request.GET else "" + ) + }) + r._csp_ignore = True + return r + if request.event.has_subevents: if 'subevent' in kwargs: self.subevent = request.event.subevents.filter(pk=kwargs['subevent'], active=True).first() @@ -286,11 +305,6 @@ class EventIndex(EventViewMixin, CartMixin, TemplateView): ) ) - context['cookie_warning'] = ( - 'require_cookie' in self.request.GET and - settings.SESSION_COOKIE_NAME not in self.request.COOKIES - ) - return context diff --git a/src/pretix/presale/views/waiting.py b/src/pretix/presale/views/waiting.py index 0c51856b00..8649a5787f 100644 --- a/src/pretix/presale/views/waiting.py +++ b/src/pretix/presale/views/waiting.py @@ -1,5 +1,6 @@ +from django.conf import settings from django.contrib import messages -from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import get_object_or_404, redirect, render from django.utils import translation from django.utils.decorators import method_decorator from django.utils.functional import cached_property @@ -7,6 +8,8 @@ from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django.views.generic import FormView from pretix.base.models.event import SubEvent +from pretix.base.templatetags.urlreplace import url_replace +from pretix.multidomain.urlreverse import eventreverse from pretix.presale.views import EventViewMixin from . import allow_frame_if_namespaced @@ -36,6 +39,23 @@ class WaitingView(EventViewMixin, FormView): ctx['item'], ctx['variation'] = self.item_and_variation return ctx + def get(self, request, *args, **kwargs): + if request.GET.get('iframe', '') == '1' and 'require_cookie' not in request.GET: + # Widget just opened. Let's to a stupid redirect to check if cookies are disabled + return redirect(request.get_full_path() + '&require_cookie=true') + elif 'require_cookie' in request.GET and settings.SESSION_COOKIE_NAME not in request.COOKIES: + # Cookies are in fact not supported. We can't even display the form, since we can't get CSRF right without + # cookies. + r = render(request, 'pretixpresale/event/cookies.html', { + 'url': eventreverse( + request.event, "presale:event.waitinglist", kwargs={'cart_namespace': kwargs.get('cart_namespace')} + ) + '?' + url_replace(request, 'require_cookie', '', 'iframe', '') + }) + r._csp_ignore = True + return r + + return super().get(request, *args, **kwargs) + @cached_property def item_and_variation(self): try: diff --git a/src/pretix/static/pretixbase/scss/error.scss b/src/pretix/static/pretixbase/scss/error.scss index 478844a8ef..4cebda8d04 100644 --- a/src/pretix/static/pretixbase/scss/error.scss +++ b/src/pretix/static/pretixbase/scss/error.scss @@ -14,3 +14,7 @@ body { font-size: 200px; color: $brand-primary; } + +.larger { + font-size: 16px; +} \ No newline at end of file diff --git a/src/pretix/static/pretixpresale/js/widget/widget.js b/src/pretix/static/pretixpresale/js/widget/widget.js index 0729f91473..f56d9cba62 100644 --- a/src/pretix/static/pretixpresale/js/widget/widget.js +++ b/src/pretix/static/pretixpresale/js/widget/widget.js @@ -166,7 +166,7 @@ Vue.component('availbox', { return 'item_' + this.item.id; } }, - order_max: function () { + order_max: function () { return this.item.has_variations ? this.variation.order_max : this.item.order_max; }, avail: function () { @@ -462,7 +462,10 @@ var shared_methods = { iframe.src = redirect_url; }, resume: function () { - var redirect_url = this.$root.event_url + 'w/' + widget_id + '/?iframe=1&locale=' + lang + '&take_cart_id=' + this.$root.cart_id; + var redirect_url = this.$root.event_url + 'w/' + widget_id + '/?iframe=1&locale=' + lang; + if (this.$root.cart_id) { + redirect_url += '&take_cart_id=' + this.$root.cart_id; + } if (this.$root.useIframe) { var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; this.$root.overlay.frame_loading = true; @@ -634,6 +637,11 @@ var shared_root_methods = { if (this.$root.useIframe) { event.preventDefault(); var url = event.target.attributes.href.value; + if (url.indexOf('?')) { + url += '&iframe=1'; + } else { + url += '?iframe=1'; + } this.$root.overlay.$children[0].$refs['frame-container'].children[0].src = url; this.$root.overlay.frame_loading = true; } else { @@ -704,7 +712,7 @@ var shared_root_computed = { if (getCookie(this.cookieName)) { form_target += "&take_cart_id=" + getCookie(this.cookieName); } - return form_target; + return form_target }, useIframe: function () { return Math.min(screen.width, window.innerWidth) >= 800 && (this.skip_ssl || site_is_secure());