Widget: pass utm-params from embedding page to presale

This commit is contained in:
Richard Schreiber
2024-03-20 09:19:02 +01:00
committed by GitHub
parent c92ca40026
commit 3651c88289
3 changed files with 79 additions and 13 deletions

View File

@@ -19,7 +19,7 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
from urllib.parse import quote from urllib.parse import quote, urlencode
from django.contrib import messages from django.contrib import messages
from django.http import Http404 from django.http import Http404
@@ -75,7 +75,8 @@ class CheckoutView(View):
return self.redirect(previous_step.get_step_url(request) if previous_step else self.get_index_url(request)) return self.redirect(previous_step.get_step_url(request) if previous_step else self.get_index_url(request))
if 'step' not in kwargs: if 'step' not in kwargs:
return self.redirect(step.get_step_url(request)) utm_params = {k: v for k, v in request.GET.items() if k.startswith("utm_")}
return self.redirect(step.get_step_url(request) + '?' + urlencode(utm_params))
is_selected = (step.identifier == kwargs.get('step', '')) is_selected = (step.identifier == kwargs.get('step', ''))
if "async_id" not in request.GET and not is_selected and not step.is_completed(request, warn=not is_selected): if "async_id" not in request.GET and not is_selected and not step.is_completed(request, warn=not is_selected):
return self.redirect(step.get_step_url(request)) return self.redirect(step.get_step_url(request))

View File

@@ -35,7 +35,6 @@
import calendar import calendar
import hashlib import hashlib
import sys import sys
import urllib.parse
from collections import defaultdict from collections import defaultdict
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from decimal import Decimal from decimal import Decimal
@@ -483,17 +482,19 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
from pretix.presale.views.cart import get_or_create_cart_id from pretix.presale.views.cart import get_or_create_cart_id
self.subevent = None self.subevent = None
utm_params = {k: v for k, v in request.GET.items() if k.startswith("utm_")}
if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET: if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET:
# User has clicked "Open in a new tab" link in widget # User has clicked "Open in a new tab" link in widget
get_or_create_cart_id(request) get_or_create_cart_id(request)
return redirect_to_url(eventreverse(request.event, 'presale:event.index', kwargs=kwargs)) return redirect_to_url(eventreverse(request.event, 'presale:event.index', kwargs=kwargs) + '?' + urlencode(utm_params))
elif request.GET.get('iframe', '') == '1' and 'take_cart_id' in request.GET: 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 # 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) get_or_create_cart_id(request)
return redirect_to_url(eventreverse(request.event, 'presale:event.index', kwargs=kwargs) + '?' + urllib.parse.urlencode({ return redirect_to_url(eventreverse(request.event, 'presale:event.index', kwargs=kwargs) + '?' + urlencode({
'require_cookie': 'true', 'require_cookie': 'true',
'cart_id': request.GET.get('take_cart_id'), 'cart_id': request.GET.get('take_cart_id'),
**({"locale": request.GET.get('locale')} if request.GET.get('locale') else {}), **({"locale": request.GET.get('locale')} if request.GET.get('locale') else {}),
**utm_params,
})) }))
elif request.GET.get('iframe', '') == '1' and len(self.request.GET.get('widget_data', '{}')) > 3: elif request.GET.get('iframe', '') == '1' and len(self.request.GET.get('widget_data', '{}')) > 3:
# We've been passed data from a widget, we need to create a cart session to store it. # We've been passed data from a widget, we need to create a cart session to store it.
@@ -504,10 +505,11 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
r = render(request, 'pretixpresale/event/cookies.html', { r = render(request, 'pretixpresale/event/cookies.html', {
'url': eventreverse( 'url': eventreverse(
request.event, "presale:event.index", kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''} request.event, "presale:event.index", kwargs={'cart_namespace': kwargs.get('cart_namespace') or ''}
) + "?" + urllib.parse.urlencode({ ) + "?" + urlencode({
"src": "widget", "src": "widget",
**({"locale": request.GET.get('locale')} if request.GET.get('locale') else {}), **({"locale": request.GET.get('locale')} if request.GET.get('locale') else {}),
**({"take_cart_id": request.GET.get('cart_id')} if request.GET.get('cart_id') else {}), **({"take_cart_id": request.GET.get('cart_id')} if request.GET.get('cart_id') else {}),
**utm_params,
}) })
}) })
r._csp_ignore = True r._csp_ignore = True
@@ -526,7 +528,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
else: else:
if 'subevent' in kwargs: if 'subevent' in kwargs:
return redirect_to_url(self.get_index_url()) return redirect_to_url(self.get_index_url() + '?' + urlencode(utm_params))
else: else:
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
@@ -802,16 +804,19 @@ class SeatingPlanView(EventViewMixin, TemplateView):
from pretix.presale.views.cart import get_or_create_cart_id from pretix.presale.views.cart import get_or_create_cart_id
self.subevent = None self.subevent = None
utm_params = {k: v for k, v in request.GET.items() if k.startswith("utm_")}
if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET: if request.GET.get('src', '') == 'widget' and 'take_cart_id' in request.GET:
# User has clicked "Open in a new tab" link in widget # User has clicked "Open in a new tab" link in widget
get_or_create_cart_id(request) get_or_create_cart_id(request)
return redirect_to_url(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs)) return redirect_to_url(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs) + '?' + urlencode(utm_params))
elif request.GET.get('iframe', '') == '1' and 'take_cart_id' in request.GET: 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 # 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) get_or_create_cart_id(request)
return redirect_to_url(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs) + '?require_cookie=true&cart_id={}'.format( return redirect_to_url(eventreverse(request.event, 'presale:event.seatingplan', kwargs=kwargs) + '?' + urlencode({
request.GET.get('take_cart_id') **utm_params,
)) 'require_cookie': 'true',
'cart_id': request.GET.get('take_cart_id'),
}))
elif request.GET.get('iframe', '') == '1' and len(self.request.GET.get('widget_data', '{}')) > 3: elif request.GET.get('iframe', '') == '1' and len(self.request.GET.get('widget_data', '{}')) > 3:
# We've been passed data from a widget, we need to create a cart session to store it. # We've been passed data from a widget, we need to create a cart session to store it.
get_or_create_cart_id(request) get_or_create_cart_id(request)
@@ -838,6 +843,10 @@ class SeatingPlanView(EventViewMixin, TemplateView):
if context['cart_redirect'].startswith('https:'): if context['cart_redirect'].startswith('https:'):
context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3] context['cart_redirect'] = '/' + context['cart_redirect'].split('/', 3)[3]
utm_params = {k: v for k, v in self.request.GET.items() if k.startswith("utm_")}
if utm_params:
context['cart_redirect'] += '?' + urlencode(utm_params)
v = self.request.GET.get('voucher') v = self.request.GET.get('voucher')
if v: if v:
v = v.strip() v = v.strip()

View File

@@ -689,6 +689,9 @@ var shared_methods = {
} else { } else {
url = url + '?iframe=1&locale=' + lang + '&take_cart_id=' + this.$root.cart_id; url = url + '?iframe=1&locale=' + lang + '&take_cart_id=' + this.$root.cart_id;
} }
if (this.$root.additionalURLParams) {
url += '&' + this.$root.additionalURLParams;
}
if (data.success === false) { if (data.success === false) {
url = url.replace(/checkout\/start/g, ""); url = url.replace(/checkout\/start/g, "");
this.$root.overlay.error_message = data.message; this.$root.overlay.error_message = data.message;
@@ -715,12 +718,27 @@ var shared_methods = {
if (this.$root.useIframe) { if (this.$root.useIframe) {
event.preventDefault(); event.preventDefault();
} else { } else {
if (this.$root.additionalURLParams) {
var params = new URLSearchParams(this.$root.additionalURLParams);
for (var [key, value] of params.entries()) {
if (!event.target.form.elements[key]) {
var input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = value;
event.target.form.appendChild(input);
}
}
}
return; return;
} }
var redirect_url = this.$root.voucherFormTarget + '&voucher=' + encodeURIComponent(this.voucher) + '&subevent=' + this.$root.subevent; var redirect_url = this.$root.voucherFormTarget + '&voucher=' + encodeURIComponent(this.voucher) + '&subevent=' + this.$root.subevent;
if (this.$root.widget_data) { if (this.$root.widget_data) {
redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json); redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
} }
if (this.$root.additionalURLParams) {
redirect_url += '&' + this.$root.additionalURLParams;
}
var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0];
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
iframe.src = redirect_url; iframe.src = redirect_url;
@@ -731,6 +749,9 @@ var shared_methods = {
if (this.$root.widget_data) { if (this.$root.widget_data) {
redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json); redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
} }
if (this.$root.additionalURLParams) {
redirect_url += '&' + this.$root.additionalURLParams;
}
if (this.$root.useIframe) { if (this.$root.useIframe) {
var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0];
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
@@ -753,6 +774,9 @@ var shared_methods = {
if (this.$root.widget_data) { if (this.$root.widget_data) {
redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json); redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
} }
if (this.$root.additionalURLParams) {
redirect_url += '&' + this.$root.additionalURLParams;
}
if (this.$root.useIframe) { if (this.$root.useIframe) {
var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0];
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
@@ -1634,9 +1658,16 @@ Vue.component('pretix-button', {
var shared_root_methods = { var shared_root_methods = {
open_link_in_frame: function (event) { open_link_in_frame: function (event) {
var url = event.target.attributes.href.value;
if (this.$root.additionalURLParams) {
if (url.indexOf('?')) {
url += '&' + this.$root.additionalURLParams;
} else {
url += '?' + this.$root.additionalURLParams;
}
}
if (this.$root.useIframe) { if (this.$root.useIframe) {
event.preventDefault(); event.preventDefault();
var url = event.target.attributes.href.value;
if (url.indexOf('?')) { if (url.indexOf('?')) {
url += '&iframe=1'; url += '&iframe=1';
} else { } else {
@@ -1645,6 +1676,7 @@ var shared_root_methods = {
this.$root.overlay.$children[0].$refs['frame-container'].children[0].src = url; this.$root.overlay.$children[0].$refs['frame-container'].children[0].src = url;
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
} else { } else {
event.target.href = url;
return; return;
} }
}, },
@@ -1801,6 +1833,9 @@ var shared_root_methods = {
if (this.$root.subevent){ if (this.$root.subevent){
redirect_url += '&subevent=' + this.$root.subevent; redirect_url += '&subevent=' + this.$root.subevent;
} }
if (this.$root.additionalURLParams) {
redirect_url += '&' + this.$root.additionalURLParams;
}
if (this.$root.useIframe) { if (this.$root.useIframe) {
var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0];
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
@@ -1824,6 +1859,9 @@ var shared_root_methods = {
if (this.$root.widget_data) { if (this.$root.widget_data) {
redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json); redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
} }
if (this.$root.additionalURLParams) {
redirect_url += '&' + this.$root.additionalURLParams;
}
if (this.$root.useIframe) { if (this.$root.useIframe) {
var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0]; var iframe = this.$root.overlay.$children[0].$refs['frame-container'].children[0];
this.$root.overlay.frame_loading = true; this.$root.overlay.frame_loading = true;
@@ -1868,6 +1906,9 @@ var shared_root_computed = {
if (this.subevent) { if (this.subevent) {
form_target += "&subevent=" + this.subevent; form_target += "&subevent=" + this.subevent;
} }
if (this.$root.additionalURLParams) {
form_target += '&' + this.$root.additionalURLParams;
}
return form_target; return form_target;
}, },
formMethod: function () { formMethod: function () {
@@ -1888,6 +1929,9 @@ var shared_root_computed = {
if (!this.$root.cart_exists) { if (!this.$root.cart_exists) {
checkout_url += "checkout/start"; checkout_url += "checkout/start";
} }
if (this.$root.additionalURLParams) {
checkout_url += '?' + this.$root.additionalURLParams;
}
var form_target = this.target_url + 'w/' + widget_id + '/cart/add?iframe=1&next=' + encodeURIComponent(checkout_url); var form_target = this.target_url + 'w/' + widget_id + '/cart/add?iframe=1&next=' + encodeURIComponent(checkout_url);
var cookie = getCookie(this.cookieName); var cookie = getCookie(this.cookieName);
if (cookie) { if (cookie) {
@@ -1924,7 +1968,19 @@ var shared_root_computed = {
}, },
widget_data_json: function () { widget_data_json: function () {
return JSON.stringify(this.widget_data); return JSON.stringify(this.widget_data);
} },
additionalURLParams: function () {
if (!window.location.search.indexOf('utm_')) {
return '';
}
var params = new URLSearchParams(window.location.search);
for (var [key, value] of params.entries()) {
if (!key.startsWith('utm_')) {
params.delete(key);
}
}
return params.toString();
},
}; };
var create_overlay = function (app) { var create_overlay = function (app) {