diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py
index 2e49e44ee..b2c86ff56 100644
--- a/src/pretix/api/serializers/organizer.py
+++ b/src/pretix/api/serializers/organizer.py
@@ -296,7 +296,14 @@ class OrganizerSettingsSerializer(SettingsSerializer):
'theme_round_borders',
'primary_font',
'organizer_logo_image_inherit',
- 'organizer_logo_image'
+ 'organizer_logo_image',
+ 'privacy_url',
+ 'cookie_consent',
+ 'cookie_consent_dialog_title',
+ 'cookie_consent_dialog_text',
+ 'cookie_consent_dialog_text_secondary',
+ 'cookie_consent_dialog_button_yes',
+ 'cookie_consent_dialog_button_no',
]
def __init__(self, *args, **kwargs):
diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py
index b5c72ba62..f1f85a4b4 100644
--- a/src/pretix/base/models/organizer.py
+++ b/src/pretix/base/models/organizer.py
@@ -97,10 +97,21 @@ class Organizer(LoggedModel):
return self.name
def save(self, *args, **kwargs):
+ is_new = not self.pk
obj = super().save(*args, **kwargs)
- self.get_cache().clear()
+ if is_new:
+ self.set_defaults()
+ else:
+ self.get_cache().clear()
return obj
+ def set_defaults(self):
+ """
+ This will be called after organizer creation.
+ This way, we can use this to introduce new default settings to pretix that do not affect existing organizers.
+ """
+ self.settings.cookie_consent = True
+
def get_cache(self):
"""
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py
index bd6ca615b..acfbd3617 100644
--- a/src/pretix/base/settings.py
+++ b/src/pretix/base/settings.py
@@ -1512,6 +1512,17 @@ DEFAULTS = {
),
'serializer_class': serializers.URLField,
},
+ 'privacy_url': {
+ 'default': None,
+ 'type': str,
+ 'form_class': forms.URLField,
+ 'form_kwargs': dict(
+ label=_("Privacy Policy URL"),
+ help_text=_("This should point e.g. to a part of your website that explains how you use data gathered in "
+ "your ticket shop."),
+ ),
+ 'serializer_class': serializers.URLField,
+ },
'confirm_texts': {
'default': LazyI18nStringList(),
'type': LazyI18nStringList,
@@ -2489,6 +2500,78 @@ Your {organizer} team"""))
'many years. If you keep it empty, gift cards do not have an explicit expiry date.'),
)
},
+ 'cookie_consent': {
+ 'default': 'False',
+ 'form_class': forms.BooleanField,
+ 'serializer_class': serializers.BooleanField,
+ 'form_kwargs': dict(
+ label=_("Enable cookie consent management features"),
+ ),
+ 'type': bool,
+ },
+ 'cookie_consent_dialog_text': {
+ 'default': LazyI18nString.from_gettext(gettext_noop(
+ 'By clicking "Accept all cookies", you agree to the storing of cookies and use of similar technologies on '
+ 'your device.'
+ )),
+ 'type': LazyI18nString,
+ 'serializer_class': I18nField,
+ 'form_class': I18nFormField,
+ 'form_kwargs': dict(
+ label=_("Dialog text"),
+ widget=I18nTextarea,
+ widget_kwargs={'attrs': {'rows': '3', 'data-display-dependency': '#id_settings-cookie_consent'}},
+ )
+ },
+ 'cookie_consent_dialog_text_secondary': {
+ 'default': LazyI18nString.from_gettext(gettext_noop(
+ 'We use cookies and similar technologies to gather data that allows us to improve this website and our '
+ 'offerings. If you do not agree, we will only use cookies if they are essential to providing the services '
+ 'this website offers. This includes cookies used to store your cart and personal settings, cookies used for '
+ 'payment processing, as well as cookies required for technical or security reasons.'
+ )),
+ 'type': LazyI18nString,
+ 'serializer_class': I18nField,
+ 'form_class': I18nFormField,
+ 'form_kwargs': dict(
+ label=_("Secondary dialog text"),
+ widget=I18nTextarea,
+ widget_kwargs={'attrs': {'rows': '3', 'data-display-dependency': '#id_settings-cookie_consent'}},
+ )
+ },
+ 'cookie_consent_dialog_title': {
+ 'default': LazyI18nString.from_gettext(gettext_noop('Privacy settings')),
+ 'type': LazyI18nString,
+ 'serializer_class': I18nField,
+ 'form_class': I18nFormField,
+ 'form_kwargs': dict(
+ label=_('Dialog title'),
+ widget=I18nTextInput,
+ widget_kwargs={'attrs': {'data-display-dependency': '#id_settings-cookie_consent'}},
+ )
+ },
+ 'cookie_consent_dialog_button_yes': {
+ 'default': LazyI18nString.from_gettext(gettext_noop('Accept all cookies')),
+ 'type': LazyI18nString,
+ 'serializer_class': I18nField,
+ 'form_class': I18nFormField,
+ 'form_kwargs': dict(
+ label=_('"Accept" button description'),
+ widget=I18nTextInput,
+ widget_kwargs={'attrs': {'data-display-dependency': '#id_settings-cookie_consent'}},
+ )
+ },
+ 'cookie_consent_dialog_button_no': {
+ 'default': LazyI18nString.from_gettext(gettext_noop('Required cookies only')),
+ 'type': LazyI18nString,
+ 'serializer_class': I18nField,
+ 'form_class': I18nFormField,
+ 'form_kwargs': dict(
+ label=_('"Reject" button description'),
+ widget=I18nTextInput,
+ widget_kwargs={'attrs': {'data-display-dependency': '#id_settings-cookie_consent'}},
+ )
+ },
'seating_choice': {
'default': 'True',
'form_class': forms.BooleanField,
diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py
index 158db11b8..82afb94a4 100644
--- a/src/pretix/control/forms/organizer.py
+++ b/src/pretix/control/forms/organizer.py
@@ -307,8 +307,14 @@ class OrganizerSettingsForm(SettingsForm):
'theme_color_danger',
'theme_color_background',
'theme_round_borders',
- 'primary_font'
-
+ 'primary_font',
+ 'privacy_url',
+ 'cookie_consent',
+ 'cookie_consent_dialog_title',
+ 'cookie_consent_dialog_text',
+ 'cookie_consent_dialog_text_secondary',
+ 'cookie_consent_dialog_button_yes',
+ 'cookie_consent_dialog_button_no',
]
organizer_logo_image = ExtFileField(
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/edit.html b/src/pretix/control/templates/pretixcontrol/organizers/edit.html
index 7f5a082f7..34bc2520e 100644
--- a/src/pretix/control/templates/pretixcontrol/organizers/edit.html
+++ b/src/pretix/control/templates/pretixcontrol/organizers/edit.html
@@ -82,6 +82,49 @@
{% bootstrap_field sform.giftcard_expiry_years layout="control" %}
{% bootstrap_field sform.giftcard_length layout="control" %}
+