Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/news/+dsgvo.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add control panel for GDPR / DSGVO settings. @davisagli
1 change: 1 addition & 0 deletions backend/news/+dsgvoTrackerPrivacy.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add tracker, tracker options and privacy URL fields to the DSGVO control panel. @iFlameing
2 changes: 2 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ lint.select = [
lint.ignore = [
# DoNotAssignLambda
"E731",
# https://docs.astral.sh/ruff/rules/suppressible-exception/
"SIM105",
]

[tool.ruff.lint.isort]
Expand Down
9 changes: 9 additions & 0 deletions backend/src/kitconcept/website/controlpanels/configure.zcml
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<configure xmlns="http://namespaces.zope.org/zope">

<adapter
factory=".dsgvo.DSGVOControlpanel"
name="dsgvo-settings"
/>
<adapter
factory=".dsgvo.DSGVOSiteEndpointExpander"
name="kitconcept.website.dsgvo"
/>

</configure>
155 changes: 155 additions & 0 deletions backend/src/kitconcept/website/controlpanels/dsgvo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from kitconcept.website import _
from kitconcept.website.interfaces import IBrowserLayer
from plone.autoform import directives
from plone.registry.interfaces import IRegistry
from plone.restapi.controlpanels import RegistryConfigletPanel
from plone.restapi.interfaces import ISiteEndpointExpander
from plone.schema import JSONField
from zope import schema
from zope.component import adapter
from zope.component import getUtility
from zope.interface import Interface
from zope.interface import implementer
from zope.schema.vocabulary import SimpleVocabulary

import json


# These are the modules supported in
# https://github.com/kitconcept/volto-dsgvo-banner/blob/main/packages/volto-dsgvo-banner/src/components/Block/View.jsx
DSGVO_MODULES = SimpleVocabulary.fromValues([
"tracking",
"youtube",
"facebook",
"google",
"vimeo",
"twitter",
])

DSGVO_TRACKERS = SimpleVocabulary.fromValues(["google", "matomo"])

TRACKER_OPTIONS_SCHEMA = json.dumps({
"type": "object",
})

PRIVACY_URL_SCHEMA = json.dumps({
"type": "object",
})


class IDSGVOSettings(Interface):
"""Settings for @kitconcept/volto-dsgvo-banner"""

show_banner = schema.Bool(
title=_("label_dsgvo_show_banner", default="Show GDPR banner on first visit"),
description=_(
"help_dsgvo_show_banner",
default="If true, the cookie consent banner will be shown immediately. "
"If false, users will be prompted to accept cookies only in the context "
"of blocks where they are needed.",
),
default=True,
)

modules = schema.List(
title=_("label_dsgvo_modules", default="Show privacy settings for"),
description=_(
"help_dsgvo_modules",
default="List of 3rd-party sites to be shown in privacy preferences.",
),
value_type=schema.Choice(
vocabulary=DSGVO_MODULES,
),
default=["tracking", "youtube", "facebook", "google"],
required=True,
)

tracker = schema.Choice(
title=_("label_dsgvo_tracker", default="Tracker"),
description=_(
"help_dsgvo_tracker",
default="Analytics tracker to use. Choose 'google' for Google Analytics "
"or 'matomo' for Matomo.",
),
vocabulary=DSGVO_TRACKERS,
required=False,
default=None,
)

directives.widget(
"tracker_options",
frontendOptions={
"widget": "modalJSONEditor",
},
)
tracker_options = JSONField(
title=_("label_dsgvo_tracker_options", default="Tracker options"),
description=_(
"help_dsgvo_tracker_options",
default="JSON object with tracker configuration. "
'For Google Analytics: {"id": "G-XXXXXXX", "gaOptions": {"anonymizeIp": true}}. '
'For Matomo: {"id": 1, "urlBase": "https://matomo.example.com/"}.',
),
schema=TRACKER_OPTIONS_SCHEMA,
required=False,
default=None,
missing_value=None,
widget="",
)

directives.widget(
"privacy_url",
frontendOptions={
"widget": "modalJSONEditor",
},
)
privacy_url = JSONField(
title=_("label_dsgvo_privacy_url", default="Privacy policy URL"),
description=_(
"help_dsgvo_privacy_url",
default="JSON object mapping language codes to privacy policy paths or URLs. "
'Example: {"en": "/en/privacy", "de": "/de/datenschutz"}.',
),
schema=PRIVACY_URL_SCHEMA,
required=False,
default=None,
missing_value=None,
widget="",
)


@adapter(Interface, Interface)
class DSGVOControlpanel(RegistryConfigletPanel):
"""REST API control panel for DSGVO settings."""

schema = IDSGVOSettings
configlet_id = "dsgvo-settings"
configlet_category_id = "plone-general"
schema_prefix = "kitconcept.website.dsgvo"


@adapter(Interface, IBrowserLayer)
@implementer(ISiteEndpointExpander)
class DSGVOSiteEndpointExpander:
"""Add DSGVO settings to the @site endpoint."""

def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self, data):
registry = getUtility(IRegistry)
settings = registry.forInterface(
IDSGVOSettings, prefix="kitconcept.website.dsgvo", check=False
)
try:
data["kitconcept.website.dsgvo"] = {
"show_banner": settings.show_banner,
"modules": settings.modules,
"tracker": settings.tracker,
"tracker_options": settings.tracker_options,
"privacy_url": settings.privacy_url,
}
except AttributeError:
# Probably the upgrade step wasn't run yet, so the records don't exist.
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2026-06-17 12:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
"Language-Code: de\n"
"Language-Name: German\n"
"Preferred-Encodings: utf-8 latin1\n"
"Domain: kitconcept.website\n"

#: kitconcept/website/distributions.zcml:17
msgid "A CMS solution for public websites. Created by kitconcept."
msgstr ""

#: kitconcept/website/profiles.zcml:14
msgid "Configure a new site based on kitconcept.website"
msgstr ""

#: kitconcept/website/profiles/default/controlpanel.xml
msgid "GDPR Settings"
msgstr "DSGVO-Einstellungen"

#. Default: "List of 3rd-party sites to be shown in privacy preferences."
#: kitconcept/website/controlpanels/dsgvo.py:56
msgid "help_dsgvo_modules"
msgstr "Liste der Drittanbieter-Dienste, die in den Datenschutzeinstellungen angezeigt werden."

#. Default: "JSON object mapping language codes to privacy policy paths or URLs. Example: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
#: kitconcept/website/controlpanels/dsgvo.py:108
#, fuzzy
msgid "help_dsgvo_privacy_url"
msgstr "JSON-Objekt, das Sprachcodes auf Pfade oder URLs zur Datenschutzrichtlinie abbildet. Beispiel: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."

#. Default: "If true, the cookie consent banner will be shown immediately. If false, users will be prompted to accept cookies only in the context of blocks where they are needed."
#: kitconcept/website/controlpanels/dsgvo.py:45
msgid "help_dsgvo_show_banner"
msgstr "Wenn aktiviert, wird das Cookie-Zustimmungsbanner sofort angezeigt. Wenn deaktiviert, werden Benutzer nur im Kontext von Blöcken, in denen Cookies benötigt werden, zur Zustimmung aufgefordert."

#. Default: "Analytics tracker to use. Choose 'google' for Google Analytics or 'matomo' for Matomo."
#: kitconcept/website/controlpanels/dsgvo.py:69
msgid "help_dsgvo_tracker"
msgstr "Zu verwendender Analytics-Tracker. Wählen Sie 'google' für Google Analytics oder 'matomo' für Matomo."

#. Default: "JSON object with tracker configuration. For Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. For Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
#: kitconcept/website/controlpanels/dsgvo.py:87
#, fuzzy
msgid "help_dsgvo_tracker_options"
msgstr "JSON-Objekt mit Tracker-Konfiguration. Für Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. Für Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."

#: kitconcept/website/distributions.zcml:17
msgid "kitconcept Website"
msgstr ""

#: kitconcept/website/profiles.zcml:14
msgid "kitconcept.website"
msgstr ""

#. Default: "Show privacy settings for"
#: kitconcept/website/controlpanels/dsgvo.py:55
msgid "label_dsgvo_modules"
msgstr "Datenschutzeinstellungen anzeigen für"

#. Default: "Privacy policy URL"
#: kitconcept/website/controlpanels/dsgvo.py:107
msgid "label_dsgvo_privacy_url"
msgstr "Datenschutzrichtlinien-URL"

#. Default: "Show GDPR banner on first visit"
#: kitconcept/website/controlpanels/dsgvo.py:44
msgid "label_dsgvo_show_banner"
msgstr "DSGVO-Banner beim ersten Besuch anzeigen"

#. Default: "Tracker"
#: kitconcept/website/controlpanels/dsgvo.py:68
msgid "label_dsgvo_tracker"
msgstr "Tracker"

#. Default: "Tracker options"
#: kitconcept/website/controlpanels/dsgvo.py:86
msgid "label_dsgvo_tracker_options"
msgstr "Tracker-Optionen"

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2026-06-17 12:10+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
"Language-Code: en\n"
"Language-Name: English\n"
"Preferred-Encodings: utf-8 latin1\n"
"Domain: kitconcept.website\n"

#: kitconcept/website/distributions.zcml:17
msgid "A CMS solution for public websites. Created by kitconcept."
msgstr ""

#: kitconcept/website/profiles.zcml:14
msgid "Configure a new site based on kitconcept.website"
msgstr ""

#: kitconcept/website/profiles/default/controlpanel.xml
msgid "GDPR Settings"
msgstr ""

#. Default: "List of 3rd-party sites to be shown in privacy preferences."
#: kitconcept/website/controlpanels/dsgvo.py:56
msgid "help_dsgvo_modules"
msgstr ""

#. Default: "JSON object mapping language codes to privacy policy paths or URLs. Example: {\"en\": \"/en/privacy\", \"de\": \"/de/datenschutz\"}."
#: kitconcept/website/controlpanels/dsgvo.py:108
msgid "help_dsgvo_privacy_url"
msgstr ""

#. Default: "If true, the cookie consent banner will be shown immediately. If false, users will be prompted to accept cookies only in the context of blocks where they are needed."
#: kitconcept/website/controlpanels/dsgvo.py:45
msgid "help_dsgvo_show_banner"
msgstr ""

#. Default: "Analytics tracker to use. Choose 'google' for Google Analytics or 'matomo' for Matomo."
#: kitconcept/website/controlpanels/dsgvo.py:69
msgid "help_dsgvo_tracker"
msgstr ""

#. Default: "JSON object with tracker configuration. For Google Analytics: {\"id\": \"G-XXXXXXX\", \"gaOptions\": {\"anonymizeIp\": true}}. For Matomo: {\"id\": 1, \"urlBase\": \"https://matomo.example.com/\"}."
#: kitconcept/website/controlpanels/dsgvo.py:87
msgid "help_dsgvo_tracker_options"
msgstr ""

#: kitconcept/website/distributions.zcml:17
msgid "kitconcept Website"
msgstr ""

#: kitconcept/website/profiles.zcml:14
msgid "kitconcept.website"
msgstr ""

#. Default: "Show privacy settings for"
#: kitconcept/website/controlpanels/dsgvo.py:55
msgid "label_dsgvo_modules"
msgstr ""

#. Default: "Privacy policy URL"
#: kitconcept/website/controlpanels/dsgvo.py:107
msgid "label_dsgvo_privacy_url"
msgstr ""

#. Default: "Show GDPR banner on first visit"
#: kitconcept/website/controlpanels/dsgvo.py:44
msgid "label_dsgvo_show_banner"
msgstr ""

#. Default: "Tracker"
#: kitconcept/website/controlpanels/dsgvo.py:68
msgid "label_dsgvo_tracker"
msgstr ""

#. Default: "Tracker options"
#: kitconcept/website/controlpanels/dsgvo.py:86
msgid "label_dsgvo_tracker_options"
msgstr ""
Loading
Loading