diff --git a/src/pretix/api/urls.py b/src/pretix/api/urls.py
index 1ad42a60e0..f5e96f1ed1 100644
--- a/src/pretix/api/urls.py
+++ b/src/pretix/api/urls.py
@@ -35,7 +35,8 @@
import importlib
from django.apps import apps
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from rest_framework import routers
from pretix.api.views import cart
diff --git a/src/pretix/base/views/redirect.py b/src/pretix/base/views/redirect.py
index 533144f99e..c5b65cd1eb 100644
--- a/src/pretix/base/views/redirect.py
+++ b/src/pretix/base/views/redirect.py
@@ -28,7 +28,7 @@ from django.urls import reverse
def _is_samesite_referer(request):
- referer = request.META.get('HTTP_REFERER')
+ referer = request.headers.get('referer')
if referer is None:
return False
diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py
index 4bfdc24951..a3ece0290a 100644
--- a/src/pretix/control/urls.py
+++ b/src/pretix/control/urls.py
@@ -33,7 +33,8 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from django.views.generic.base import RedirectView
from pretix.control.views import (
diff --git a/src/pretix/control/views/dashboards.py b/src/pretix/control/views/dashboards.py
index 66446a33aa..50746d131d 100644
--- a/src/pretix/control/views/dashboards.py
+++ b/src/pretix/control/views/dashboards.py
@@ -51,7 +51,7 @@ from django.utils import formats
from django.utils.formats import date_format
from django.utils.html import escape
from django.utils.timezone import now
-from django.utils.translation import gettext_lazy as _, pgettext, ungettext
+from django.utils.translation import gettext_lazy as _, ngettext, pgettext
from pretix.base.decimal import round_decimal
from pretix.base.models import (
@@ -555,7 +555,7 @@ def widgets_for_event_qs(request, qs, user, nmax, lazy=False):
'event': event.slug,
'organizer': event.organizer.slug
}),
- orders_text=ungettext('{num} order', '{num} orders', event.order_count or 0).format(
+ orders_text=ngettext('{num} order', '{num} orders', event.order_count or 0).format(
num=event.order_count or 0
)
) if user.has_active_staff_session(request.session.session_key) or event.pk in events_with_orders else ''
diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py
index 631231c736..fddca01036 100644
--- a/src/pretix/control/views/orders.py
+++ b/src/pretix/control/views/orders.py
@@ -62,7 +62,7 @@ from django.urls import reverse
from django.utils import formats
from django.utils.formats import date_format, get_format
from django.utils.functional import cached_property
-from django.utils.http import is_safe_url
+from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import make_aware, now
from django.utils.translation import gettext, gettext_lazy as _, ngettext
from django.views.generic import (
@@ -680,7 +680,7 @@ class OrderRefundCancel(OrderView):
messages.success(self.request, _('The refund has been canceled.'))
else:
messages.error(self.request, _('This refund can not be canceled at the moment.'))
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
return redirect(self.request.GET.get("next"))
return redirect(self.get_order_url())
@@ -716,7 +716,7 @@ class OrderRefundProcess(OrderView):
messages.success(self.request, _('The refund has been processed.'))
else:
messages.error(self.request, _('This refund can not be processed at the moment.'))
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
return redirect(self.request.GET.get("next"))
return redirect(self.get_order_url())
@@ -742,7 +742,7 @@ class OrderRefundDone(OrderView):
messages.success(self.request, _('The refund has been marked as done.'))
else:
messages.error(self.request, _('This refund can not be processed at the moment.'))
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
return redirect(self.request.GET.get("next"))
return redirect(self.get_order_url())
diff --git a/src/pretix/control/views/waitinglist.py b/src/pretix/control/views/waitinglist.py
index 4881aba7a1..ee775665cb 100644
--- a/src/pretix/control/views/waitinglist.py
+++ b/src/pretix/control/views/waitinglist.py
@@ -43,7 +43,7 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.functional import cached_property
-from django.utils.http import is_safe_url
+from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext
from django.views import View
@@ -144,7 +144,7 @@ class WaitingListActionView(EventPermissionRequiredMixin, WaitingListQuerySetMix
permission = 'can_change_orders'
def _redirect_back(self):
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
return redirect(self.request.GET.get("next"))
return redirect(reverse('control:event.orders.waitinglist', kwargs={
'event': self.request.event.slug,
@@ -360,7 +360,7 @@ class EntryDelete(EventPermissionRequiredMixin, DeleteView):
self.object.log_action('pretix.event.orders.waitinglist.deleted', user=self.request.user)
self.object.delete()
messages.success(self.request, _('The selected entry has been deleted.'))
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
return redirect(self.request.GET.get("next"))
return HttpResponseRedirect(success_url)
diff --git a/src/pretix/helpers/http.py b/src/pretix/helpers/http.py
index eec2b437c5..47f5752b99 100644
--- a/src/pretix/helpers/http.py
+++ b/src/pretix/helpers/http.py
@@ -38,7 +38,7 @@ class ChunkBasedFileResponse(StreamingHttpResponse):
def get_client_ip(request):
ip = request.META.get('REMOTE_ADDR')
if settings.TRUST_X_FORWARDED_FOR:
- x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+ x_forwarded_for = request.headers.get('x-forwarded-for')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
return ip
diff --git a/src/pretix/multidomain/event_domain_urlconf.py b/src/pretix/multidomain/event_domain_urlconf.py
index 2aea8ca743..29987671c6 100644
--- a/src/pretix/multidomain/event_domain_urlconf.py
+++ b/src/pretix/multidomain/event_domain_urlconf.py
@@ -22,7 +22,8 @@
import importlib.util
from django.apps import apps
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import event_patterns, locale_patterns
diff --git a/src/pretix/multidomain/maindomain_urlconf.py b/src/pretix/multidomain/maindomain_urlconf.py
index 61f8980f5e..b03dbfce6b 100644
--- a/src/pretix/multidomain/maindomain_urlconf.py
+++ b/src/pretix/multidomain/maindomain_urlconf.py
@@ -35,7 +35,8 @@
import importlib.util
from django.apps import apps
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from django.views.generic import TemplateView
from pretix.multidomain.plugin_handler import plugin_event_urls
diff --git a/src/pretix/multidomain/organizer_domain_urlconf.py b/src/pretix/multidomain/organizer_domain_urlconf.py
index 65e8708842..e7098096a1 100644
--- a/src/pretix/multidomain/organizer_domain_urlconf.py
+++ b/src/pretix/multidomain/organizer_domain_urlconf.py
@@ -22,7 +22,8 @@
import importlib.util
from django.apps import apps
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import (
diff --git a/src/pretix/plugins/paypal/urls.py b/src/pretix/plugins/paypal/urls.py
index cb373ddf25..0a29004270 100644
--- a/src/pretix/plugins/paypal/urls.py
+++ b/src/pretix/plugins/paypal/urls.py
@@ -19,7 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from .views import abort, oauth_disconnect, redirect_view, success
diff --git a/src/pretix/plugins/paypal2/urls.py b/src/pretix/plugins/paypal2/urls.py
index e49ca964ae..f85b71864b 100644
--- a/src/pretix/plugins/paypal2/urls.py
+++ b/src/pretix/plugins/paypal2/urls.py
@@ -19,7 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from .views import (
PayView, XHRView, abort, isu_disconnect, isu_return, redirect_view,
diff --git a/src/pretix/plugins/stripe/urls.py b/src/pretix/plugins/stripe/urls.py
index 011a3cf98a..dbcf9d45c9 100644
--- a/src/pretix/plugins/stripe/urls.py
+++ b/src/pretix/plugins/stripe/urls.py
@@ -19,7 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from pretix.multidomain import event_url
diff --git a/src/pretix/presale/urls.py b/src/pretix/presale/urls.py
index 0a63c61704..2d8b0ad476 100644
--- a/src/pretix/presale/urls.py
+++ b/src/pretix/presale/urls.py
@@ -32,7 +32,8 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from django.views.decorators.csrf import csrf_exempt
import pretix.presale.views.cart
diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py
index 5650c65312..3f287b7f02 100644
--- a/src/pretix/presale/views/cart.py
+++ b/src/pretix/presale/views/cart.py
@@ -48,7 +48,7 @@ from django.utils import translation
from django.utils.crypto import get_random_string
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
-from django.utils.http import is_safe_url, url_has_allowed_host_and_scheme
+from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.timezone import now
from django.utils.translation import gettext as _, pgettext
from django.views.decorators.clickjacking import xframe_options_exempt
@@ -83,7 +83,7 @@ except:
class CartActionMixin:
def get_next_url(self):
- if "next" in self.request.GET and is_safe_url(self.request.GET.get("next"), allowed_hosts=None):
+ if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
u = self.request.GET.get('next')
else:
kwargs = {}
@@ -106,7 +106,7 @@ class CartActionMixin:
return self.get_next_url()
def get_error_url(self):
- if "next_error" in self.request.GET and is_safe_url(self.request.GET.get("next_error"), allowed_hosts=None):
+ if "next_error" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next_error"), allowed_hosts=None):
u = self.request.GET.get('next_error')
if '?' in u:
u += '&require_cookie=true'
diff --git a/src/pretix/urls.py b/src/pretix/urls.py
index 3d6d96d645..3fd42ea801 100644
--- a/src/pretix/urls.py
+++ b/src/pretix/urls.py
@@ -33,7 +33,8 @@
# License for the specific language governing permissions and limitations under the License.
from django.conf import settings
-from django.conf.urls import include, re_path
+from django.conf.urls import re_path
+from django.urls import include
from django.views.generic import RedirectView
import pretix.control.urls
diff --git a/src/tests/api/test_checkin.py b/src/tests/api/test_checkin.py
index 6ef20442e4..9132e9af89 100644
--- a/src/tests/api/test_checkin.py
+++ b/src/tests/api/test_checkin.py
@@ -23,8 +23,6 @@ import datetime
import time
from decimal import Decimal
from unittest import mock
-# deprecated: from django.utils.http import urlquote
-# use urlib instead
from urllib.parse import quote as urlquote
import pytest
diff --git a/src/tests/testdummy/__init__.py b/src/tests/testdummy/__init__.py
index 7bff28a9a5..9fd5bdc500 100644
--- a/src/tests/testdummy/__init__.py
+++ b/src/tests/testdummy/__init__.py
@@ -19,19 +19,3 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# .
#
-from django.apps import AppConfig
-
-
-class TestDummyApp(AppConfig):
- name = 'tests.testdummy'
- verbose_name = '.testdummy'
-
- class PretixPluginMeta:
- name = '.testdummy'
- version = '1.0.0'
-
- def ready(self):
- from tests.testdummy import signals # noqa
-
-
-default_app_config = 'tests.testdummy.TestDummyApp'
diff --git a/src/tests/testdummy/apps.py b/src/tests/testdummy/apps.py
new file mode 100644
index 0000000000..ea89f7ce8b
--- /dev/null
+++ b/src/tests/testdummy/apps.py
@@ -0,0 +1,34 @@
+#
+# This file is part of pretix (Community Edition).
+#
+# Copyright (C) 2014-2020 Raphael Michel and contributors
+# Copyright (C) 2020-2021 rami.io GmbH and contributors
+#
+# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
+# Public License as published by the Free Software Foundation in version 3 of the License.
+#
+# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
+# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
+# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
+# this file, see .
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+# .
+#
+from django.apps import AppConfig
+
+
+class TestDummyApp(AppConfig):
+ name = 'tests.testdummy'
+ verbose_name = '.testdummy'
+
+ class PretixPluginMeta:
+ name = '.testdummy'
+ version = '1.0.0'
+
+ def ready(self):
+ from tests.testdummy import signals # noqa