diff --git a/cookie_consent/conf.py b/cookie_consent/conf.py index 4e23d48..c57423d 100644 --- a/cookie_consent/conf.py +++ b/cookie_consent/conf.py @@ -1,6 +1,7 @@ from django.conf import settings # NOQA from appconf import AppConf +from django.urls import reverse_lazy __all__ = ["settings"] @@ -24,3 +25,5 @@ class CookieConsentConf(AppConf): CACHE_BACKEND = "default" LOG_ENABLED = True + + SUCCESS_URL = reverse_lazy("cookie_consent_cookie_group_list") diff --git a/cookie_consent/views.py b/cookie_consent/views.py index aae3cf6..fd742ce 100644 --- a/cookie_consent/views.py +++ b/cookie_consent/views.py @@ -6,6 +6,7 @@ from django.utils.http import url_has_allowed_host_and_scheme from django.views.generic import ListView, View +from .conf import settings from .models import CookieGroup from .util import ( accept_cookies, @@ -48,7 +49,7 @@ def get_success_url(self): require_https=self.request.is_secure(), ): raise SuspiciousOperation("Unsafe open redirect suspected.") - return redirect_to or reverse("cookie_consent_cookie_group_list") + return redirect_to or settings.COOKIE_CONSENT_SUCCESS_URL def process(self, request, response, varname): # pragma: no cover raise NotImplementedError() diff --git a/docs/settings.rst b/docs/settings.rst index f1fa95b..843c4d7 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -66,3 +66,8 @@ for more details about the meaning. Boolean value represents if user actions when they accepting and declining cookies will be logged. Turning it off might be useful for preventing your database from getting filled up with log items. Default: ``True`` + +``COOKIE_CONSENT_SUCCESS_URL`` + The success URL to redirect the user too after a successful accept/decline action. If + a ``?next`` parameter is present in the request, then it takes priority over this + setting. Defaults to the URL of the built-in cookie list view. diff --git a/tests/test_views.py b/tests/test_views.py index dd7c13e..4fe695d 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,7 +1,10 @@ -from django.test import TestCase +from django.test import Client, TestCase from django.test.utils import override_settings from django.urls import reverse +import pytest +from pytest_django.asserts import assertRedirects + from cookie_consent.models import ( ACTION_ACCEPTED, ACTION_DECLINED, @@ -11,21 +14,36 @@ ) -class CookieGroupBaseProcessViewTests(TestCase): - def test_get_success_url(self): - """ - If user adds a 'next' as URL parameter it should, - redirect to the value of 'next' - """ - expected_url = reverse("test_page") - url = "{}?next={}".format(reverse("cookie_consent_accept_all"), expected_url) - response = self.client.post(url, follow=True) - self.assertRedirects(response, expected_url) - - def test_no_open_redirects(self): - url = "{}?next=https://evil.com".format(reverse("cookie_consent_accept_all")) - response = self.client.post(url, follow=True) - self.assertEqual(response.status_code, 400) # result of SupiciousOperation +@pytest.mark.django_db +def test_processing_get_success_url(client: Client): + """ + If user adds a 'next' as URL parameter it should, + redirect to the value of 'next' + """ + expected_url = reverse("test_page") + url = "{}?next={}".format(reverse("cookie_consent_accept_all"), expected_url) + + response = client.post(url, follow=True) + + assertRedirects(response, expected_url) + + +@pytest.mark.django_db +def test_processing_no_open_redirects(client: Client): + url = "{}?next=https://evil.com".format(reverse("cookie_consent_accept_all")) + + response = client.post(url, follow=True) + + assert response.status_code == 400 # result of SupiciousOperation + + +@pytest.mark.django_db +def test_alternative_redirect_fallback(client: Client, settings): + settings.COOKIE_CONSENT_SUCCESS_URL = "/alternative" + + response = client.post(reverse("cookie_consent_accept_all"), follow=False) + + assertRedirects(response, "/alternative", fetch_redirect_response=False) class IntegrationTest(TestCase):