Skip to content

Commit

Permalink
Merge pull request #3504 from open-formulieren/feature/cookie-consent…
Browse files Browse the repository at this point in the history
…-bar

Dynamic cookie consent bar
  • Loading branch information
sergei-maertens authored Oct 6, 2023
2 parents 248779a + ed3a2c0 commit a1e5b11
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 179 deletions.
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ django-capture-tag==1.0
# via -r requirements/base.in
django-colorfield==0.9.0
# via -r requirements/base.in
django-cookie-consent==0.4.0
django-cookie-consent==0.5.0b0
# via -r requirements/base.in
django-cors-headers==3.11.0
# via -r requirements/base.in
Expand Down
6 changes: 3 additions & 3 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ django-colorfield==0.9.0
# via
# -c requirements/base.txt
# -r requirements/base.txt
django-cookie-consent==0.4.0
django-cookie-consent==0.5.0b0
# via
# -c requirements/base.txt
# -r requirements/base.txt
Expand Down Expand Up @@ -454,7 +454,7 @@ glom==20.11.0
# -c requirements/base.txt
# -r requirements/base.txt
# mozilla-django-oidc-db
greenlet==2.0.1
greenlet==2.0.2
# via playwright
html5lib==1.1
# via
Expand Down Expand Up @@ -645,7 +645,7 @@ platformdirs==2.2.0
# -r requirements/base.txt
# black
# zeep
playwright==1.30.0
playwright==1.38.0
# via -r requirements/test-tools.in
pluggy==0.13.1
# via pytest
Expand Down
6 changes: 3 additions & 3 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ django-colorfield==0.9.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
django-cookie-consent==0.4.0
django-cookie-consent==0.5.0b0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
Expand Down Expand Up @@ -511,7 +511,7 @@ glom==20.11.0
# mozilla-django-oidc-db
gprof2dot==2021.2.21
# via django-silk
greenlet==2.0.1
greenlet==2.0.2
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
Expand Down Expand Up @@ -744,7 +744,7 @@ platformdirs==2.2.0
# -r requirements/ci.txt
# black
# zeep
playwright==1.30.0
playwright==1.38.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
Expand Down
2 changes: 1 addition & 1 deletion requirements/extensions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ django-colorfield==0.9.0
# via
# -c requirements/base.in
# -r requirements/base.txt
django-cookie-consent==0.4.0
django-cookie-consent==0.5.0b0
# via
# -c requirements/base.in
# -r requirements/base.txt
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{% include "analytics_tools/siteimprove.html" with request=request only %}
<template class="analytics-scripts">
{% include "analytics_tools/siteimprove.html" with request=request only %}
</template>
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{% include "analytics_tools/google.html" with request=request only %}
{% include "analytics_tools/piwik.html" with request=request only %}
{% include "analytics_tools/piwik_pro.html" with request=request only %}
{% include "analytics_tools/matomo.html" with request=request only %}
<template class="analytics-scripts">
{% include "analytics_tools/google.html" with request=request only %}
{% include "analytics_tools/piwik.html" with request=request only %}
{% include "analytics_tools/piwik_pro.html" with request=request only %}
{% include "analytics_tools/matomo.html" with request=request only %}
</template>
40 changes: 16 additions & 24 deletions src/openforms/analytics_tools/tests/test_analytics_rendering.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from django.test import override_settings
from django.urls import reverse

from cookie_consent.models import CookieGroup
from django_webtest import WebTest

from openforms.analytics_tools.models import AnalyticsToolsConfiguration
from openforms.forms.tests.factories import FormFactory
from openforms.utils.tests.cache import clear_caches
from openforms.tests.utils import NOOP_CACHES


@override_settings(CACHES=NOOP_CACHES)
class AnalyticsToolsRenderingTest(WebTest):
"""Integration tests for rendering of analytics snippets.
Expand All @@ -19,11 +21,11 @@ class AnalyticsToolsRenderingTest(WebTest):

@classmethod
def setUpTestData(cls):
clear_caches()
super().setUpTestData()
form = FormFactory.create()
cls.url = reverse("forms:form-detail", kwargs={"slug": form.slug})
config = AnalyticsToolsConfiguration.get_solo()
assert isinstance(config, AnalyticsToolsConfiguration)
config.analytics_cookie_consent_group, _ = CookieGroup.objects.get_or_create(
varname="analytical"
)
Expand All @@ -39,17 +41,19 @@ def test_google_analytics_rendering(self):
self.config.ga_code = "UA-XXXXX-Y"
self.config.save()

# Accept cookies
form_page = self.app.get(self.url)
accept_form = form_page.forms[0]
refreshed_form_page = accept_form.submit().follow()

google_tag_manager = refreshed_form_page.pyquery("#google-tag-manager")
google_analytics = refreshed_form_page.pyquery("#google-analytics")

google_tag_manager = form_page.pyquery("#google-tag-manager")
google_analytics = form_page.pyquery("#google-analytics")
self.assertTrue(google_tag_manager.is_("script"))
self.assertTrue(google_analytics.is_("script"))

# Regression test for #1587
with self.subTest("script CSP nonces"):
scripts = form_page.pyquery("script[nonce]")
for script in scripts:
self.assertTrue(bool(script.attrib["nonce"]))

def test_matomo_rendering(self):
"""Assert that the Matomo script is rendered"""

Expand All @@ -61,11 +65,8 @@ def test_matomo_rendering(self):

# Accept cookies
form_page = self.app.get(self.url)
accept_form = form_page.forms[0]
refreshed_form_page = accept_form.submit().follow()

matomo = refreshed_form_page.pyquery("#matomo-analytics")

matomo = form_page.pyquery("#matomo-analytics")
self.assertTrue(matomo.is_("script"))

def test_piwik_pro_rendering(self):
Expand All @@ -79,11 +80,8 @@ def test_piwik_pro_rendering(self):

# Accept cookies
form_page = self.app.get(self.url)
accept_form = form_page.forms[0]
refreshed_form_page = accept_form.submit().follow()

piwik_pro = refreshed_form_page.pyquery("#piwik-pro-analytics")

piwik_pro = form_page.pyquery("#piwik-pro-analytics")
self.assertTrue(piwik_pro.is_("script"))

def test_piwik_rendering(self):
Expand All @@ -97,11 +95,8 @@ def test_piwik_rendering(self):

# Accept cookies
form_page = self.app.get(self.url)
accept_form = form_page.forms[0]
refreshed_form_page = accept_form.submit().follow()

piwik = refreshed_form_page.pyquery("#piwik-analytics")

piwik = form_page.pyquery("#piwik-analytics")
self.assertTrue(piwik.is_("script"))

def test_site_improve_rendering(self):
Expand All @@ -115,9 +110,6 @@ def test_site_improve_rendering(self):

# Accept cookies
form_page = self.app.get(self.url)
accept_form = form_page.forms[0]
refreshed_form_page = accept_form.submit().follow()

siteimprove = refreshed_form_page.pyquery("#siteimprove-analytics")

siteimprove = form_page.pyquery("#siteimprove-analytics")
self.assertTrue(siteimprove.is_("script"))
21 changes: 0 additions & 21 deletions src/openforms/forms/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import tempfile
from io import BytesIO
from unittest.mock import patch

from django.core.files import File
from django.test import override_settings
Expand Down Expand Up @@ -96,26 +95,6 @@ def test_design_tokens_rendered(self):
style_node.text(), ":root { --of-layout-background: #ffffff; }"
)

@patch(
"cookie_consent.templatetags.cookie_consent_tags.get_cookie_value_from_request",
return_value=True,
)
def test_analytics_get_csp_nonce(self, mock_cookies_accepted):
"""
Assert that the analytics scripts correctly receive the CSP nonce.
Regression test for #1587
"""
# enable google analytics
self.config.ga_code = "UA-XXXXX-Y"
self.config.save()

form_page = self.app.get(self.url)

scripts = form_page.pyquery("script[nonce]")
for script in scripts:
self.assertTrue(bool(script.attrib["nonce"]))

@override_settings(MEDIA_ROOT=tempfile.mkdtemp())
def test_theme_stylesheets_included(self):
"""
Expand Down
91 changes: 55 additions & 36 deletions src/openforms/templates/includes/cookie-notice.html
Original file line number Diff line number Diff line change
@@ -1,42 +1,61 @@
{% load i18n cookie_consent_tags %}

{% not_accepted_or_declined_cookie_groups request as cookie_groups %}
{% load i18n static cookie_consent_tags %}

{% static "cookie_consent/cookiebar.module.js" as cookiebar_src %}
{% url 'cookie_consent_cookie_group_list' as manage_url %}
{% url 'cookie_consent_status' as status_url %}

{% if request.path != manage_url %}

{% all_cookie_groups 'cookie-consent__cookie-groups' %}

<template id="cookie-consent__cookie-bar">
<section class="cookie-notice" aria-label="{% trans 'Cookie notice' %}">

{% if cookie_groups and request.path != manage_url %}
<div class="cookie-notice">
<span class="cookie-notice__text">
{% blocktrans trimmed %}
We use cookies to optimize and improve our website and services.
You can <a class="utrecht-link utrecht-link--openforms" href="{{ manage_url }}">manage your preferences</a>.
{% endblocktrans %}
</span>

<span class="cookie-notice__text">
{% blocktrans trimmed %}
We use cookies to optimize and improve our website and services.
You can <a class="utrecht-link utrecht-link--openforms" href="{{ manage_url }}">manage your preferences</a>.
{% endblocktrans %}
</span>
<div class="openforms-toolbar">
<ul class="openforms-toolbar__list">
<li class="openforms-toolbar__list-item">
<button
type="submit"
class="utrecht-button utrecht-button--primary-action openforms-button openforms-button--primary cookie-notice__accept"
>{% trans "Accept all" %}</button>
</li>
<li class="openforms-toolbar__list-item">
<button
type="submit"
class="utrecht-button utrecht-button--primary-action openforms-button openforms-button--primary cookie-notice__decline"
>{% trans "Decline all" %}</button>
</li>
</ul>
</div>
</section>
</template>

<div class="openforms-toolbar">
<ul class="openforms-toolbar__list">
<li class="openforms-toolbar__list-item">
<form action="{% url 'cookie_consent_accept_all' %}" method="post" class="cookie-notice__form cookie-notice__form--accept">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.build_absolute_uri }}" />
<button
type="submit"
class="utrecht-button utrecht-button--primary-action openforms-button openforms-button--primary"
>{% trans "Accept all" %}</button>
</form>
</li>
<li class="openforms-toolbar__list-item">
<form action="{% url 'cookie_consent_decline_all' %}" method="post" class="cookie-notice__form cookie-notice__form--decline">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.build_absolute_uri }}" />
<button
type="submit"
class="utrecht-button utrecht-button--primary-action openforms-button openforms-button--primary"
>{% trans "Decline all" %}</button>
</form>
</li>
</ul>
</div>
</div>
<script type="module" nonce="{{ request.csp_nonce }}">
import {showCookieBar} from '{{ cookiebar_src }}';
const varName = '{{ analytics_varname|escapejs }}';
showCookieBar({
statusUrl: '{{ status_url|escapejs }}',
templateSelector: '#cookie-consent__cookie-bar',
cookieGroupsSelector: '#cookie-consent__cookie-groups',
acceptSelector: '.cookie-notice__accept',
declineSelector: '.cookie-notice__decline',
insertBefore: '#cookie-consent__cookie-bar',
onAccept: (groups) => {
const isAnalyticsEnabled = groups.find(group => group.varname === varName);
if (!isAnalyticsEnabled) return;
const analyticsTemplateNodes = document.querySelectorAll('.analytics-scripts');
analyticsTemplateNodes.forEach(templateNode => {
const clone = templateNode.content.cloneNode(true);
templateNode.parentNode.insertBefore(clone, templateNode);
})
},
});
</script>
{% endif %}
15 changes: 6 additions & 9 deletions src/openforms/templates/master.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@
{% if config.theme_stylesheet %}<link href="{{ config.theme_stylesheet }}" media="all" rel="stylesheet" />{% endif %}
{% if config.theme_stylesheet_file %}<link href="{{ config.theme_stylesheet_file.url }}" media="all" rel="stylesheet" />{% endif %}

{% if enable_analytics %}
{# Load the various supported analytics provider snippets #}
{% include "analytics_tools/all_head.html" %}
{% endif %}
{# Load the various supported analytics provider snippets - they are activated after consent #}
{% include "analytics_tools/all_head.html" with analytics_varname=analytics_varname %}
</head>

<body class="view__body">
{# No point in putting this in a <template> tag, since it targets noscript #}
{% if enable_analytics and analytics_tools_config.enable_google_analytics and analytics_tools_config.gtm_code %}
{# Load the second part of the Google tag manager snippet #}
<!-- Google Tag Manager (noscript) -->
Expand All @@ -43,15 +42,13 @@
{% endblock %}

{% block footer %}
{% include "includes/cookie-notice.html" %}
{% include "includes/cookie-notice.html" with analytics_varname=analytics_varname %}
{% endblock %}

<script src="{% static 'bundles/public.js' %}"></script>
{% block extra_js %}{% endblock %}
{% if enable_analytics %}
{# Load the various supported analytics provider snippets #}
{% include "analytics_tools/all_bottom.html" %}
{% endif %}
{# Load the various supported analytics provider snippets - they are activated after consent #}
{% include "analytics_tools/all_bottom.html" with analytics_varname=analytics_varname %}
</body>
</html>
{% endwith %}
Loading

0 comments on commit a1e5b11

Please sign in to comment.