Compare commits

..
16 changed files with 84 additions and 101 deletions
+2 -1
View File
@@ -10,7 +10,8 @@ tests:
- cd src
- python manage.py check
- make all compress
- PRETIX_CONFIG_FILE=tests/ci_sqlite.cfg py.test -n 3 tests --ignore=tests/e2e --maxfail=100
- playwright install
- PRETIX_CONFIG_FILE=tests/ci_sqlite.cfg py.test -n 3 tests --maxfail=100
except:
- '/^v.*$/'
pypi:
+57 -9
View File
@@ -65,16 +65,48 @@ def get_supported_language(requested_language, allowed_languages, default_langua
return language
class LocaleMiddleware(MiddlewareMixin):
class BaseLocaleMiddleware(MiddlewareMixin):
"""
This middleware sets the correct locale and timezone
for a request.
This is a reduced LocaleMiddleware that uses only information contained in the WSGI request data
to figure out the language (cookie and browser settings). We need it to have a consistent language
for error pages that are generated from the middleware stack before we know e.g. which user is logged
in or which event is selected.
"""
def process_request(self, request: HttpRequest):
language = get_language_from_early_request(request)
translation.activate(language)
set_region(None)
request.LANGUAGE_CODE = language
timezone.deactivate()
def process_response(self, request: HttpRequest, response: HttpResponse):
language = translation.get_language()
patch_vary_headers(response, ('Accept-Language',))
if 'Content-Language' not in response:
response['Content-Language'] = language
return response
class LocaleMiddleware(MiddlewareMixin):
"""
This is the full LocaleMiddleware that uses all available information to figure out the correct
language for the request using all available sources, in this order of priority:
- Backend: User settings
- Language cookie
- Frontend: Customer account settings
- Browser settings
- Frontend: Event/Organizer settings
- System default
It needs to run late in the middleware stack to have all information available for these steps.
For some cases, it is even ran a second time since the event is sometimes only figured out after the
middleware stack (can happen for plugin views).
"""
def process_request(self, request: HttpRequest):
language = get_language_from_request(request)
region = None
# Normally, this middleware runs *before* the event is set. However, on event frontend pages it
# might be run a second time by pretix.presale.EventMiddleware and in this case the event is already
# set and can be taken into account for the decision.
@@ -95,16 +127,15 @@ class LocaleMiddleware(MiddlewareMixin):
if '-' not in language and settings_holder.settings.region:
language += '-' + settings_holder.settings.region
if settings_holder.settings.region:
region = settings_holder.settings.region
set_region(settings_holder.settings.region)
else:
gs = global_settings_object(request)
if '-' not in language and gs.settings.region:
language += '-' + gs.settings.region
if gs.settings.region:
region = gs.settings.region
set_region(gs.settings.region)
translation.activate(language)
set_region(region)
request.LANGUAGE_CODE = get_language_without_region()
tzname = None
@@ -184,6 +215,24 @@ def get_default_language():
return settings.LANGUAGE_CODE
def get_language_from_early_request(request: HttpRequest) -> str:
"""
Analyzes the request to find what language the user wants the system to
show using only WSGI-available information. Only languages listed in
settings.LANGUAGES are taken into account. If the user requests a sublanguage
where we have a main language, we send out the main language.
"""
global _supported
if _supported is None:
_supported = OrderedDict(settings.LANGUAGES)
return (
get_language_from_cookie(request)
or get_language_from_browser(request)
or get_default_language()
)
def get_language_from_request(request: HttpRequest) -> str:
"""
Analyzes the request to find what language the user wants the system to
@@ -198,7 +247,6 @@ def get_language_from_request(request: HttpRequest) -> str:
if request.path.startswith(get_script_prefix() + 'control'):
return (
get_language_from_user_settings(request)
or get_language_from_customer_settings(request)
or get_language_from_cookie(request)
or get_language_from_browser(request)
or get_language_from_event(request)
+1 -1
View File
@@ -11,7 +11,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<link rel="icon" href="{% static "pretixbase/img/favicon.ico" %}">
<script type="text/javascript" src="{% static "pretixbase/js/errors.js" %}"></script>
{% block custom_header %}{% endblock %}
{% if css_theme %}
<link rel="stylesheet" type="text/css" href="{{ css_theme }}" />
@@ -21,5 +20,6 @@
<div class="container">
{% block content %}{% endblock %}
</div>
<script src="{% static "pretixbase/js/errors.js" %}"></script>
</body>
</html>
+1 -7
View File
@@ -1342,13 +1342,7 @@ class QuestionAnswerFilterForm(forms.Form):
opqs = opqs.filter(canceled=False)
if fdata.get("item", "") != "":
i = fdata.get("item", "")
if '-' in i:
opqs = opqs.filter(
item_id=i.split('-')[0],
variation_id=i.split('-')[1],
)
else:
opqs = opqs.filter(item_id=i)
opqs = opqs.filter(item_id__in=(i,))
return opqs
@@ -66,7 +66,6 @@
<script type="text/javascript" src="{% static "lightbox/js/lightbox.js" %}"></script>
<script type="text/javascript" src="{% static "are-you-sure/jquery.are-you-sure.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/errors.js" %}"></script>
{% endcompress %}
{{ html_head|safe }}
@@ -270,18 +270,18 @@ class ReportExporter(ReportlabExportMixin, BaseExporter):
def _transaction_group_header_label(self):
return _("Event") + " / " + _("Product")
def _transaction_group(self, form_data, r):
def _transaction_group_label(self, form_data, r):
if not self.is_multievent and not form_data.get("split_subevents"):
return None, None
return None
if r.get("subevent_id"):
return "{} - {} ({}) [{}]".format(
r["order__event__name"],
r["subevent__name"],
date_format(r["subevent__date_from"]),
r["order__event__slug"]
), f"subevent-{r['subevent_id']}"
)
else:
return "{} [{}]".format(r["order__event__name"], r["order__event__slug"]), f"event-{r['order__event__slug']}"
return "{} [{}]".format(r["order__event__name"], r["order__event__slug"])
def _transaction_row_label(self, r):
if r["item_id"]:
@@ -343,17 +343,17 @@ class ReportExporter(ReportlabExportMixin, BaseExporter):
last_group = None
last_group_head_idx = 0
for r in qs:
group_label, group_id = self._transaction_group(form_data, r)
e = self._transaction_group_label(form_data, r)
if group_id != last_group:
if last_group_head_idx > 0 and group_id is not None:
if e != last_group:
if last_group_head_idx > 0 and e is not None:
tdata[last_group_head_idx][4] = Paragraph(money_filter(sum_price_by_group - sum_tax_by_group, currency), tstyle_bold_right),
tdata[last_group_head_idx][5] = Paragraph(money_filter(sum_tax_by_group, currency), tstyle_bold_right),
tdata[last_group_head_idx][6] = Paragraph(money_filter(sum_price_by_group, currency), tstyle_bold_right),
tdata.append(
[
FontFallbackParagraph(
group_label,
e,
tstyle_bold,
),
"",
@@ -367,7 +367,7 @@ class ReportExporter(ReportlabExportMixin, BaseExporter):
tstyledata.append(
("SPAN", (0, len(tdata) - 1), (3, len(tdata) - 1)),
)
last_group = group_id
last_group = e
last_group_head_idx = len(tdata) - 1
sum_price_by_group = Decimal("0.00")
sum_tax_by_group = Decimal("0.00")
@@ -9,7 +9,7 @@
{% load anonymize_email %}
{% block thetitle %}
{% if messages %}
{{ messages|join:" " }} ::
{{ messages|join:" " }} ::
{% endif %}
{% block title %}{% endblock %}{% if request.resolver_match.url_name != "event.index" %} :: {% endif %}{{ event.name }}
{% endblock %}
@@ -1,7 +1,6 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load l10n %}
{% load static %}
{% load eventurl %}
{% load cache_large %}
{% load money %}
@@ -40,7 +39,6 @@
{% else %}
<meta property="og:url" content="{% abseventurl request.event "presale:event.index" %}" />
{% endif %}
<script type="text/javascript" src="{% static "pretixpresale/js/csrfcookieretry.js" %}"></script>
{% endblock %}
{% block content %}
@@ -6,7 +6,6 @@
{% load money %}
{% load expiresformat %}
{% load eventurl %}
{% load static %}
{% load phone_format %}
{% load rich_text %}
{% load getitem %}
@@ -23,10 +22,6 @@
{% endif %}
{% trans "Order details" %}
{% endblock %}
{% block custom_header %}
{{ block.super }}
<script type="text/javascript" src="{% static "pretixpresale/js/csrfcookieretry.js" %}"></script>
{% endblock %}
{% block content %}
{% if "thanks" in request.GET or "paid" in request.GET %}
<div class="thank-you">
@@ -22,5 +22,4 @@
<script type="text/javascript" src="{% static "pretixpresale/js/ui/iframe.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/deanonymize_email.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/errors.js" %}"></script>
{% endcompress %}
+1
View File
@@ -503,6 +503,7 @@ REST_FRAMEWORK = {
MIDDLEWARE = [
'pretix.helpers.logs.RequestIdMiddleware',
'pretix.base.middleware.BaseLocaleMiddleware',
'pretix.api.middleware.IdempotencyMiddleware',
'pretix.multidomain.middlewares.MultiDomainMiddleware',
'pretix.base.middleware.CustomCommonMiddleware',
+2 -3
View File
@@ -174,16 +174,15 @@ function async_task_error(jqXHR, textStatus, errorThrown) {
var respdom = $(jqXHR.responseText);
var c = respdom.filter('.container');
if (respdom.filter('form') && (respdom.filter('.has-error') || respdom.filter('.alert-danger'))) {
// This is a failed form validation, let's just use it
if (respdom.filter('#page-wrapper') && $('#page-wrapper').length) {
// This is a failed form validation, let's just use it
async_task_replace_page("#page-wrapper", respdom.find("#page-wrapper").html());
} else {
async_task_replace_page("body", jqXHR.responseText.substring(
jqXHR.responseText.indexOf("<body"),
jqXHR.responseText.indexOf("</body")
));
document.dispatchEvent(new Event("pretix:async-task-error"))
}
} else if (c.length > 0) {
+5 -11
View File
@@ -1,11 +1,5 @@
['DOMContentLoaded', 'pretix:async-task-error'].forEach(function (ev) {
document.addEventListener(ev, function () {
document.querySelectorAll('#goback, #reload').forEach(function (element) {
const regularLoad = ev === 'DOMContentLoaded' && element.id === 'goback';
element.addEventListener('click', regularLoad
? () => window.history.back()
: () => window.location.reload()
);
});
});
});
document.getElementById('goback').onclick =
function() {window.history.back()};
document.getElementById('reload').onclick =
function() {window.location.reload(true)};
@@ -1,15 +0,0 @@
document.addEventListener("DOMContentLoaded", () => {
const COOKIE_NAME = "__Host-pretix_csrftoken";
const RELOAD_FLAG = "csrfReloadPerformed";
const hasCookie = document.cookie
.split("; ")
.some((c) => c.startsWith(COOKIE_NAME + "="));
if (!hasCookie && !sessionStorage.getItem(RELOAD_FLAG)) {
sessionStorage.setItem(RELOAD_FLAG, "1");
location.reload();
} else if (hasCookie && sessionStorage.getItem(RELOAD_FLAG)) {
sessionStorage.removeItem(RELOAD_FLAG);
}
});
@@ -2051,16 +2051,9 @@ var shared_root_methods = {
this.$root.set_cart_id(data.cart_id);
this.$root.overlay.frame_loading = false;
callback()
}, (xhr, data) => {
if (xhr.status === 429 && typeof xhr.responseURL !== "undefined") {
this.$root.overlay.error_message = strings['cart_error_429'];
this.$root.overlay.frame_loading = false;
this.$root.overlay.error_url_after = this.$root.newTabTarget;
this.$root.overlay.error_url_after_new_tab = true;
} else {
}, () => {
this.$root.overlay.error_message = strings['cart_error'];
this.$root.overlay.frame_loading = false;
}
})
},
get_cart_id: function() {
@@ -2149,14 +2142,7 @@ var shared_root_computed = {
if (this.subevent) {
target = this.target_url + this.subevent + '/';
}
var parameters = this.$root.consent_parameter
if (this.$root.additionalURLParams) {
parameters += `&${this.$root.additionalURLParams}`
}
if (parameters) {
target += '?' + parameters.replace(/^&/, '')
}
return target
return target;
},
useIframe: function () {
if (window.crossOriginIsolated === true) {
@@ -162,15 +162,7 @@ export function createWidgetStore (config: {
return params.toString()
},
newTabTarget (): string {
let url = this.subevent ? `${this.targetUrl}${this.subevent}/` : this.targetUrl
let parameters = this.consentParameter
if (this.additionalURLParams) {
parameters += `&${this.additionalURLParams}`
}
if (parameters) {
url += '?' + parameters.replace(/^&/, '')
}
return url
return this.subevent ? `${this.targetUrl}${this.subevent}/` : this.targetUrl
},
formTarget (): string {
const isFirefox = navigator.userAgent.toLowerCase().includes('firefox')
@@ -449,7 +441,6 @@ export function createWidgetStore (config: {
this.overlay.frameLoading = false
this.overlay.errorUrlAfter = this.newTabTarget
this.overlay.errorUrlAfterNewTab = true
return
} else if (e.status === 405) {
// Likely a redirect!
this.targetUrl = e.responseUrl.substring(0, e.responseUrl.indexOf('/cart/add') - 18)
@@ -469,18 +460,11 @@ export function createWidgetStore (config: {
this.overlay.frameLoading = true
const data = await createCart(url)
this.setCartId(data.cart_id)
return true
} catch (e) {
if (e instanceof ApiError && e.status === 429) {
this.overlay.errorMessage = STRINGS.cart_error_429
this.overlay.frameLoading = false
this.overlay.errorUrlAfter = this.newTabTarget
this.overlay.errorUrlAfterNewTab = true
} else if (e instanceof ApiError && (e.status === 200 || (e.status >= 400 && e.status < 500))) {
if (e instanceof ApiError && (e.status === 200 || (e.status >= 400 && e.status < 500))) {
this.overlay.errorMessage = STRINGS.cart_error
this.overlay.frameLoading = false
}
return false
}
},
redeem (voucherCode: string, event?: Event) {
@@ -500,7 +484,7 @@ export function createWidgetStore (config: {
async resume () {
if (!this.cartId && this.keepCart) {
// create an empty cart whose id we can persist
if (!await this.createCart()) return
await this.createCart()
}
let redirectUrl = `${this.targetUrl}w/${globalWidgetId}/`
if (this.subevent && this.isButton && this.items.length === 0) {