django-cookie-consent 0.4.0.dev0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/AUTHORS +1 -0
- {django-cookie-consent-0.4.0.dev0/django_cookie_consent.egg-info → django_cookie_consent-0.6.0}/PKG-INFO +45 -11
- django_cookie_consent-0.6.0/cookie_consent/__init__.py +1 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/cache.py +17 -11
- django_cookie_consent-0.6.0/cookie_consent/migrations/0003_alter_cookiegroup_varname.py +32 -0
- django_cookie_consent-0.6.0/cookie_consent/migrations/0004_cookie_natural_key.py +19 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/models.py +89 -18
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/static/cookie_consent/cookiebar.js +2 -1
- django_cookie_consent-0.6.0/cookie_consent/static/cookie_consent/cookiebar.module.js +163 -0
- django_cookie_consent-0.6.0/cookie_consent/static/cookie_consent/cookiebar.module.js.map +7 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/templatetags/cookie_consent_tags.py +39 -9
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/urls.py +15 -9
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/util.py +28 -11
- django_cookie_consent-0.6.0/cookie_consent/views.py +117 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0/django_cookie_consent.egg-info}/PKG-INFO +45 -11
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/django_cookie_consent.egg-info/SOURCES.txt +10 -3
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/django_cookie_consent.egg-info/requires.txt +2 -5
- django_cookie_consent-0.6.0/pyproject.toml +111 -0
- django_cookie_consent-0.6.0/setup.cfg +10 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/tests/test_cache.py +4 -1
- django_cookie_consent-0.6.0/tests/test_cookie_group_model.py +19 -0
- django_cookie_consent-0.6.0/tests/test_cookie_model.py +24 -0
- django_cookie_consent-0.6.0/tests/test_javascript_cookiebar.py +84 -0
- django_cookie_consent-0.6.0/tests/test_legacy_javascript_cookiebar.py +78 -0
- django_cookie_consent-0.6.0/tests/test_models.py +124 -0
- django_cookie_consent-0.6.0/tests/test_templatetags.py +50 -0
- django-cookie-consent-0.4.0.dev0/cookie_consent/__init__.py +0 -1
- django-cookie-consent-0.4.0.dev0/cookie_consent/compat.py +0 -11
- django-cookie-consent-0.4.0.dev0/cookie_consent/views.py +0 -67
- django-cookie-consent-0.4.0.dev0/django_cookie_consent.egg-info/not-zip-safe +0 -1
- django-cookie-consent-0.4.0.dev0/setup.cfg +0 -102
- django-cookie-consent-0.4.0.dev0/setup.py +0 -3
- django-cookie-consent-0.4.0.dev0/tests/test_models.py +0 -53
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/LICENSE +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/MANIFEST.in +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/README.md +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/admin.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/apps.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/conf.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/fixtures/common_cookies.json +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/middleware.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/migrations/0001_initial.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/migrations/0002_auto__add_logitem.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/migrations/__init__.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/templates/cookie_consent/_cookie_group.html +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/templates/cookie_consent/base.html +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/templates/cookie_consent/cookiegroup_list.html +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/cookie_consent/templatetags/__init__.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/django_cookie_consent.egg-info/dependency_links.txt +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/django_cookie_consent.egg-info/top_level.txt +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/tests/test_middleware.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/tests/test_settings.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/tests/test_util.py +0 -0
- {django-cookie-consent-0.4.0.dev0 → django_cookie_consent-0.6.0}/tests/test_views.py +0 -0
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-cookie-consent
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Django cookie consent application
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Author-email: Informatika Mihelac <bmihelac@mihelac.org>
|
|
6
|
+
License: Copyright (c) Bojan Mihelac and individual contributors.
|
|
7
|
+
All rights reserved.
|
|
8
|
+
|
|
9
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
10
|
+
are permitted provided that the following conditions are met:
|
|
11
|
+
|
|
12
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer.
|
|
14
|
+
|
|
15
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
16
|
+
notice, this list of conditions and the following disclaimer in the
|
|
17
|
+
documentation and/or other materials provided with the distribution.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
20
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
21
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
23
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
24
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
25
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
26
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
+
|
|
9
30
|
Project-URL: Documentation, https://django-cookie-consent.readthedocs.io/en/latest/
|
|
10
31
|
Project-URL: Changelog, https://github.com/jazzband/django-cookie-consent/blob/master/docs/changelog.rst
|
|
11
32
|
Project-URL: Bug Tracker, https://github.com/jazzband/django-cookie-consent/issues
|
|
12
33
|
Project-URL: Source Code, https://github.com/jazzband/django-cookie-consent
|
|
13
34
|
Keywords: cookies,cookie-consent,cookie bar
|
|
14
|
-
Classifier: Development Status ::
|
|
35
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
36
|
Classifier: Framework :: Django
|
|
16
|
-
Classifier: Framework :: Django :: 3.2
|
|
17
|
-
Classifier: Framework :: Django :: 4.1
|
|
18
37
|
Classifier: Framework :: Django :: 4.2
|
|
38
|
+
Classifier: Framework :: Django :: 5.0
|
|
19
39
|
Classifier: Intended Audience :: Developers
|
|
20
40
|
Classifier: License :: OSI Approved :: BSD License
|
|
21
41
|
Classifier: Operating System :: Unix
|
|
@@ -26,15 +46,29 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
26
46
|
Classifier: Programming Language :: Python :: 3.9
|
|
27
47
|
Classifier: Programming Language :: Python :: 3.10
|
|
28
48
|
Classifier: Programming Language :: Python :: 3.11
|
|
49
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
29
50
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
51
|
+
Requires-Python: >=3.8
|
|
30
52
|
Description-Content-Type: text/markdown
|
|
53
|
+
License-File: LICENSE
|
|
54
|
+
License-File: AUTHORS
|
|
55
|
+
Requires-Dist: django>=4.2
|
|
56
|
+
Requires-Dist: django-appconf
|
|
31
57
|
Provides-Extra: tests
|
|
32
|
-
|
|
58
|
+
Requires-Dist: pytest; extra == "tests"
|
|
59
|
+
Requires-Dist: pytest-django; extra == "tests"
|
|
60
|
+
Requires-Dist: pytest-playwright; extra == "tests"
|
|
61
|
+
Requires-Dist: tox; extra == "tests"
|
|
62
|
+
Requires-Dist: isort; extra == "tests"
|
|
63
|
+
Requires-Dist: black; extra == "tests"
|
|
64
|
+
Requires-Dist: flake8; extra == "tests"
|
|
33
65
|
Provides-Extra: coverage
|
|
66
|
+
Requires-Dist: pytest-cov; extra == "coverage"
|
|
34
67
|
Provides-Extra: docs
|
|
68
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
69
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
35
70
|
Provides-Extra: release
|
|
36
|
-
|
|
37
|
-
License-File: AUTHORS
|
|
71
|
+
Requires-Dist: tbump; extra == "release"
|
|
38
72
|
|
|
39
73
|
Django cookie consent
|
|
40
74
|
=====================
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.6.0"
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
from django.core.cache import caches
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from .conf import settings
|
|
5
|
+
from .models import CookieGroup
|
|
5
6
|
|
|
6
7
|
CACHE_KEY = "cookie_consent_cache"
|
|
7
|
-
CACHE_TIMEOUT = 60 * 60
|
|
8
|
+
CACHE_TIMEOUT = 60 * 60 # 60 minutes
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def _get_cache():
|
|
@@ -23,17 +24,22 @@ def delete_cache():
|
|
|
23
24
|
cache.delete(CACHE_KEY)
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
def _get_cookie_groups_from_db():
|
|
28
|
+
qs = CookieGroup.objects.filter(is_required=False).prefetch_related("cookie_set")
|
|
29
|
+
return qs.in_bulk(field_name="varname")
|
|
30
|
+
|
|
31
|
+
|
|
26
32
|
def all_cookie_groups():
|
|
33
|
+
"""
|
|
34
|
+
Get all cookie groups that are optional.
|
|
35
|
+
|
|
36
|
+
Reads from the cache where possible, sets the value in the cache if there's a
|
|
37
|
+
cache miss.
|
|
38
|
+
"""
|
|
27
39
|
cache = _get_cache()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
qs = CookieGroup.objects.filter(is_required=False)
|
|
33
|
-
qs = qs.prefetch_related("cookie_set")
|
|
34
|
-
items = dict([(g.varname, g) for g in qs])
|
|
35
|
-
cache.set(CACHE_KEY, items, CACHE_TIMEOUT)
|
|
36
|
-
return items
|
|
40
|
+
return cache.get_or_set(
|
|
41
|
+
CACHE_KEY, _get_cookie_groups_from_db, timeout=CACHE_TIMEOUT
|
|
42
|
+
)
|
|
37
43
|
|
|
38
44
|
|
|
39
45
|
def get_cookie_group(varname):
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Generated by Django 4.2.13 on 2024-05-09 19:01
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
import django.core.validators
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
("cookie_consent", "0002_auto__add_logitem"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AlterField(
|
|
17
|
+
model_name="cookiegroup",
|
|
18
|
+
name="varname",
|
|
19
|
+
field=models.CharField(
|
|
20
|
+
max_length=32,
|
|
21
|
+
unique=True,
|
|
22
|
+
validators=[
|
|
23
|
+
django.core.validators.RegexValidator(
|
|
24
|
+
re.compile("^[-_a-zA-Z0-9]+$"),
|
|
25
|
+
"Enter a valid 'varname' consisting of letters, numbers, underscores or hyphens.",
|
|
26
|
+
"invalid",
|
|
27
|
+
)
|
|
28
|
+
],
|
|
29
|
+
verbose_name="Variable name",
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generated by Django 4.2.13 on 2024-05-09 20:22
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("cookie_consent", "0003_alter_cookiegroup_varname"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddConstraint(
|
|
14
|
+
model_name="cookie",
|
|
15
|
+
constraint=models.UniqueConstraint(
|
|
16
|
+
fields=("cookiegroup", "name", "domain"), name="natural_key"
|
|
17
|
+
),
|
|
18
|
+
),
|
|
19
|
+
]
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import re
|
|
3
|
+
from typing import TypedDict
|
|
3
4
|
|
|
4
5
|
from django.core.validators import RegexValidator
|
|
5
6
|
from django.db import models
|
|
6
7
|
from django.utils.translation import gettext_lazy as _
|
|
7
8
|
|
|
8
|
-
from cookie_consent.cache import delete_cache
|
|
9
|
-
|
|
10
9
|
COOKIE_NAME_RE = re.compile(r"^[-_a-zA-Z0-9]+$")
|
|
11
10
|
validate_cookie_name = RegexValidator(
|
|
12
11
|
COOKIE_NAME_RE,
|
|
@@ -18,9 +17,48 @@ validate_cookie_name = RegexValidator(
|
|
|
18
17
|
)
|
|
19
18
|
|
|
20
19
|
|
|
20
|
+
def clear_cache_after(func):
|
|
21
|
+
def wrapper(*args, **kwargs):
|
|
22
|
+
from .cache import delete_cache
|
|
23
|
+
|
|
24
|
+
return_value = func(*args, **kwargs)
|
|
25
|
+
delete_cache()
|
|
26
|
+
return return_value
|
|
27
|
+
|
|
28
|
+
return wrapper
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CookieGroupDict(TypedDict):
|
|
32
|
+
varname: str
|
|
33
|
+
name: str
|
|
34
|
+
description: str
|
|
35
|
+
is_required: bool
|
|
36
|
+
# TODO: should we output this? page cache busting would be
|
|
37
|
+
# required if we do this. Alternatively, set up a JSONView to output these?
|
|
38
|
+
# version: str
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class BaseQueryset(models.query.QuerySet):
|
|
42
|
+
@clear_cache_after
|
|
43
|
+
def delete(self):
|
|
44
|
+
return super().delete()
|
|
45
|
+
|
|
46
|
+
@clear_cache_after
|
|
47
|
+
def update(self, **kwargs):
|
|
48
|
+
return super().update(**kwargs)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CookieGroupManager(models.Manager.from_queryset(BaseQueryset)):
|
|
52
|
+
def get_by_natural_key(self, varname):
|
|
53
|
+
return self.get(varname=varname)
|
|
54
|
+
|
|
55
|
+
|
|
21
56
|
class CookieGroup(models.Model):
|
|
22
57
|
varname = models.CharField(
|
|
23
|
-
_("Variable name"),
|
|
58
|
+
_("Variable name"),
|
|
59
|
+
max_length=32,
|
|
60
|
+
unique=True,
|
|
61
|
+
validators=[validate_cookie_name],
|
|
24
62
|
)
|
|
25
63
|
name = models.CharField(_("Name"), max_length=100, blank=True)
|
|
26
64
|
description = models.TextField(_("Description"), blank=True)
|
|
@@ -37,6 +75,8 @@ class CookieGroup(models.Model):
|
|
|
37
75
|
ordering = models.IntegerField(_("Ordering"), default=0)
|
|
38
76
|
created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True)
|
|
39
77
|
|
|
78
|
+
objects = CookieGroupManager()
|
|
79
|
+
|
|
40
80
|
class Meta:
|
|
41
81
|
verbose_name = _("Cookie Group")
|
|
42
82
|
verbose_name_plural = _("Cookie Groups")
|
|
@@ -45,19 +85,37 @@ class CookieGroup(models.Model):
|
|
|
45
85
|
def __str__(self):
|
|
46
86
|
return self.name
|
|
47
87
|
|
|
48
|
-
|
|
88
|
+
@clear_cache_after
|
|
89
|
+
def save(self, *args, **kwargs):
|
|
90
|
+
super().save(*args, **kwargs)
|
|
91
|
+
|
|
92
|
+
@clear_cache_after
|
|
93
|
+
def delete(self, *args, **kwargs):
|
|
94
|
+
return super().delete(*args, **kwargs)
|
|
95
|
+
|
|
96
|
+
def natural_key(self):
|
|
97
|
+
return (self.varname,)
|
|
98
|
+
|
|
99
|
+
def get_version(self) -> str:
|
|
49
100
|
try:
|
|
50
101
|
return str(self.cookie_set.all()[0].get_version())
|
|
51
102
|
except IndexError:
|
|
52
103
|
return ""
|
|
53
104
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
105
|
+
def for_json(self) -> CookieGroupDict:
|
|
106
|
+
return {
|
|
107
|
+
"varname": self.varname,
|
|
108
|
+
"name": self.name,
|
|
109
|
+
"description": self.description,
|
|
110
|
+
"is_required": self.is_required,
|
|
111
|
+
# "version": self.get_version(),
|
|
112
|
+
}
|
|
57
113
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
114
|
+
|
|
115
|
+
class CookieManager(models.Manager.from_queryset(BaseQueryset)):
|
|
116
|
+
def get_by_natural_key(self, name, domain, cookiegroup):
|
|
117
|
+
group = CookieGroup.objects.get_by_natural_key(cookiegroup)
|
|
118
|
+
return self.get(cookiegroup=group, name=name, domain=domain)
|
|
61
119
|
|
|
62
120
|
|
|
63
121
|
class Cookie(models.Model):
|
|
@@ -72,14 +130,35 @@ class Cookie(models.Model):
|
|
|
72
130
|
domain = models.CharField(_("Domain"), max_length=250, blank=True)
|
|
73
131
|
created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True)
|
|
74
132
|
|
|
133
|
+
objects = CookieManager()
|
|
134
|
+
|
|
75
135
|
class Meta:
|
|
76
136
|
verbose_name = _("Cookie")
|
|
77
137
|
verbose_name_plural = _("Cookies")
|
|
138
|
+
constraints = [
|
|
139
|
+
models.UniqueConstraint(
|
|
140
|
+
fields=("cookiegroup", "name", "domain"),
|
|
141
|
+
name="natural_key",
|
|
142
|
+
),
|
|
143
|
+
]
|
|
78
144
|
ordering = ["-created"]
|
|
79
145
|
|
|
80
146
|
def __str__(self):
|
|
81
147
|
return "%s %s%s" % (self.name, self.domain, self.path)
|
|
82
148
|
|
|
149
|
+
@clear_cache_after
|
|
150
|
+
def save(self, *args, **kwargs):
|
|
151
|
+
super().save(*args, **kwargs)
|
|
152
|
+
|
|
153
|
+
@clear_cache_after
|
|
154
|
+
def delete(self, *args, **kwargs):
|
|
155
|
+
return super().delete(*args, **kwargs)
|
|
156
|
+
|
|
157
|
+
def natural_key(self):
|
|
158
|
+
return (self.name, self.domain) + self.cookiegroup.natural_key()
|
|
159
|
+
|
|
160
|
+
natural_key.dependencies = ["cookie_consent.cookiegroup"]
|
|
161
|
+
|
|
83
162
|
@property
|
|
84
163
|
def varname(self):
|
|
85
164
|
return "%s=%s:%s" % (self.cookiegroup.varname, self.name, self.domain)
|
|
@@ -87,14 +166,6 @@ class Cookie(models.Model):
|
|
|
87
166
|
def get_version(self):
|
|
88
167
|
return self.created.isoformat()
|
|
89
168
|
|
|
90
|
-
def delete(self, *args, **kwargs):
|
|
91
|
-
super(Cookie, self).delete(*args, **kwargs)
|
|
92
|
-
delete_cache()
|
|
93
|
-
|
|
94
|
-
def save(self, *args, **kwargs):
|
|
95
|
-
super(Cookie, self).save(*args, **kwargs)
|
|
96
|
-
delete_cache()
|
|
97
|
-
|
|
98
169
|
|
|
99
170
|
ACTION_ACCEPTED = 1
|
|
100
171
|
ACTION_DECLINED = -1
|
|
@@ -10,7 +10,7 @@ function evalXCookieConsent(script) {
|
|
|
10
10
|
script.remove();
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function
|
|
13
|
+
function lecacyShowCookieBar (options) {
|
|
14
14
|
const defaults = {
|
|
15
15
|
content: '',
|
|
16
16
|
cookie_groups: [],
|
|
@@ -64,3 +64,4 @@ function showCookieBar (options) {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
window.legacyShowCookieBar = window.showCookieBar = lecacyShowCookieBar;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// src/cookiebar.ts
|
|
2
|
+
var DEFAULT_FETCH_HEADERS = {
|
|
3
|
+
"X-Cookie-Consent-Fetch": "1"
|
|
4
|
+
};
|
|
5
|
+
var FetchClient = class {
|
|
6
|
+
constructor(statusUrl, csrfHeaderName) {
|
|
7
|
+
this.statusUrl = statusUrl;
|
|
8
|
+
this.csrfHeaderName = csrfHeaderName;
|
|
9
|
+
this.cookieStatus = null;
|
|
10
|
+
}
|
|
11
|
+
async getCookieStatus() {
|
|
12
|
+
if (this.cookieStatus === null) {
|
|
13
|
+
const response = await window.fetch(
|
|
14
|
+
this.statusUrl,
|
|
15
|
+
{
|
|
16
|
+
method: "GET",
|
|
17
|
+
credentials: "same-origin",
|
|
18
|
+
headers: DEFAULT_FETCH_HEADERS
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
this.cookieStatus = await response.json();
|
|
22
|
+
}
|
|
23
|
+
if (this.cookieStatus === null) {
|
|
24
|
+
throw new Error("Unexpectedly received null cookie status");
|
|
25
|
+
}
|
|
26
|
+
return this.cookieStatus;
|
|
27
|
+
}
|
|
28
|
+
async saveCookiesStatusBackend(urlProperty) {
|
|
29
|
+
const cookieStatus = await this.getCookieStatus();
|
|
30
|
+
const url = cookieStatus[urlProperty];
|
|
31
|
+
if (!url) {
|
|
32
|
+
throw new Error(`Missing url for ${urlProperty} - was the cookie status not loaded properly?`);
|
|
33
|
+
}
|
|
34
|
+
await window.fetch(url, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
credentials: "same-origin",
|
|
37
|
+
headers: {
|
|
38
|
+
...DEFAULT_FETCH_HEADERS,
|
|
39
|
+
[this.csrfHeaderName]: cookieStatus.csrftoken
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var loadCookieGroups = (selector) => {
|
|
45
|
+
const node = document.querySelector(selector);
|
|
46
|
+
if (!node) {
|
|
47
|
+
throw new Error(`No cookie groups (script) tag found, using selector: '${selector}'`);
|
|
48
|
+
}
|
|
49
|
+
return JSON.parse(node.innerText);
|
|
50
|
+
};
|
|
51
|
+
var doInsertBefore = (beforeNode, newNode) => {
|
|
52
|
+
const parent = beforeNode.parentNode;
|
|
53
|
+
if (parent === null)
|
|
54
|
+
throw new Error("Reference node doesn't have a parent.");
|
|
55
|
+
parent.insertBefore(newNode, beforeNode);
|
|
56
|
+
};
|
|
57
|
+
var registerEvents = ({
|
|
58
|
+
client,
|
|
59
|
+
cookieBarNode,
|
|
60
|
+
cookieGroups,
|
|
61
|
+
acceptSelector,
|
|
62
|
+
onAccept,
|
|
63
|
+
declineSelector,
|
|
64
|
+
onDecline,
|
|
65
|
+
acceptedCookieGroups: accepted,
|
|
66
|
+
declinedCookieGroups: declined,
|
|
67
|
+
notAcceptedOrDeclinedCookieGroups: undecided
|
|
68
|
+
}) => {
|
|
69
|
+
const acceptNode = cookieBarNode.querySelector(acceptSelector);
|
|
70
|
+
if (acceptNode) {
|
|
71
|
+
acceptNode.addEventListener("click", (event) => {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
const acceptedGroups = filterCookieGroups(cookieGroups, accepted.concat(undecided));
|
|
74
|
+
onAccept == null ? void 0 : onAccept(acceptedGroups, event);
|
|
75
|
+
client.saveCookiesStatusBackend("acceptUrl");
|
|
76
|
+
cookieBarNode.parentNode.removeChild(cookieBarNode);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const declineNode = cookieBarNode.querySelector(declineSelector);
|
|
80
|
+
if (declineNode) {
|
|
81
|
+
declineNode.addEventListener("click", (event) => {
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
const declinedGroups = filterCookieGroups(cookieGroups, declined.concat(undecided));
|
|
84
|
+
onDecline == null ? void 0 : onDecline(declinedGroups, event);
|
|
85
|
+
client.saveCookiesStatusBackend("declineUrl");
|
|
86
|
+
cookieBarNode.parentNode.removeChild(cookieBarNode);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var filterCookieGroups = (cookieGroups, varNames) => {
|
|
91
|
+
return cookieGroups.filter((group) => varNames.includes(group.varname));
|
|
92
|
+
};
|
|
93
|
+
function cloneNode(node) {
|
|
94
|
+
return node.cloneNode(true);
|
|
95
|
+
}
|
|
96
|
+
var showCookieBar = async (options = {}) => {
|
|
97
|
+
const {
|
|
98
|
+
templateSelector = "#cookie-consent__cookie-bar",
|
|
99
|
+
cookieGroupsSelector = "#cookie-consent__cookie-groups",
|
|
100
|
+
acceptSelector = ".cookie-consent__accept",
|
|
101
|
+
declineSelector = ".cookie-consent__decline",
|
|
102
|
+
insertBefore = null,
|
|
103
|
+
onShow,
|
|
104
|
+
onAccept,
|
|
105
|
+
onDecline,
|
|
106
|
+
statusUrl = "",
|
|
107
|
+
csrfHeaderName = "X-CSRFToken"
|
|
108
|
+
// Django's default, can be overridden with settings.CSRF_HEADER_NAME
|
|
109
|
+
} = options;
|
|
110
|
+
const cookieGroups = loadCookieGroups(cookieGroupsSelector);
|
|
111
|
+
if (!cookieGroups.length)
|
|
112
|
+
return;
|
|
113
|
+
const templateNode = document.querySelector(templateSelector);
|
|
114
|
+
if (!templateNode) {
|
|
115
|
+
throw new Error(`No (template) element found for selector '${templateSelector}'.`);
|
|
116
|
+
}
|
|
117
|
+
const doInsert = insertBefore === null ? (cookieBarNode2) => document.querySelector("body").appendChild(cookieBarNode2) : typeof insertBefore === "string" ? (cookieBarNode2) => {
|
|
118
|
+
const referenceNode = document.querySelector(insertBefore);
|
|
119
|
+
if (referenceNode === null)
|
|
120
|
+
throw new Error(`No element found for selector '${insertBefore}'.`);
|
|
121
|
+
doInsertBefore(referenceNode, cookieBarNode2);
|
|
122
|
+
} : (cookieBarNode2) => doInsertBefore(insertBefore, cookieBarNode2);
|
|
123
|
+
if (!statusUrl)
|
|
124
|
+
throw new Error("Missing status URL option, did you forget to pass the `statusUrl` option?");
|
|
125
|
+
const client = new FetchClient(statusUrl, csrfHeaderName);
|
|
126
|
+
const cookieStatus = await client.getCookieStatus();
|
|
127
|
+
const {
|
|
128
|
+
acceptedCookieGroups,
|
|
129
|
+
declinedCookieGroups,
|
|
130
|
+
notAcceptedOrDeclinedCookieGroups
|
|
131
|
+
} = cookieStatus;
|
|
132
|
+
const acceptedGroups = filterCookieGroups(cookieGroups, acceptedCookieGroups);
|
|
133
|
+
if (acceptedGroups.length)
|
|
134
|
+
onAccept == null ? void 0 : onAccept(acceptedGroups);
|
|
135
|
+
const declinedGroups = filterCookieGroups(cookieGroups, declinedCookieGroups);
|
|
136
|
+
if (declinedGroups.length)
|
|
137
|
+
onDecline == null ? void 0 : onDecline(declinedGroups);
|
|
138
|
+
if (!notAcceptedOrDeclinedCookieGroups.length)
|
|
139
|
+
return;
|
|
140
|
+
const childToClone = templateNode.content.firstElementChild;
|
|
141
|
+
if (childToClone === null)
|
|
142
|
+
throw new Error("The cookie bar template element may not be empty.");
|
|
143
|
+
const cookieBarNode = cloneNode(childToClone);
|
|
144
|
+
registerEvents({
|
|
145
|
+
client,
|
|
146
|
+
cookieBarNode,
|
|
147
|
+
cookieGroups,
|
|
148
|
+
acceptSelector,
|
|
149
|
+
onAccept,
|
|
150
|
+
declineSelector,
|
|
151
|
+
onDecline,
|
|
152
|
+
acceptedCookieGroups,
|
|
153
|
+
declinedCookieGroups,
|
|
154
|
+
notAcceptedOrDeclinedCookieGroups
|
|
155
|
+
});
|
|
156
|
+
doInsert(cookieBarNode);
|
|
157
|
+
onShow == null ? void 0 : onShow();
|
|
158
|
+
};
|
|
159
|
+
export {
|
|
160
|
+
loadCookieGroups,
|
|
161
|
+
showCookieBar
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=cookiebar.module.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../js/src/cookiebar.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Cookiebar functionality, as a TS/JS module.\n *\n * About modules: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\n *\n * The code is organized here in a way to make the templates work with Django's page\n * cache. This means that anything user-specific (so different django session and even\n * cookie consent cookies) cannot be baked into the templates, as that breaks caches.\n *\n * The cookie bar operates on the following principles:\n *\n * - The developer using the library includes the desired template in their django\n * templates, using the HTML <template> element. This contains the content for the\n * cookie bar.\n * - The developer is responsible for loading some Javascript that loads this script.\n * - The main export of this script needs to be called (showCookieBar), with the\n * appropriate options.\n * - The options include the backend URLs where the retrieve data, which selectors/DOM\n * nodes to use for various functionality and the hooks to tap into the accept/decline\n * life-cycle.\n * - When a user accepts or declines (all) cookies, the call to the backend is made via\n * a fetch request, bypassing any page caches and preventing full-page reloads.\n */\n\n/**\n * A serialized cookie group.\n *\n * See the backend model method `CookieGroup.as_json()`.\n */\nexport interface CookieGroup {\n varname: string;\n name: string;\n description: string;\n is_required: boolean;\n}\n\nexport interface Options {\n statusUrl: string;\n // TODO: also accept element rather than selector?\n templateSelector: string;\n /**\n * DOM selector to the (script) tag holding the JSON-serialized cookie groups.\n *\n * This is typically rendered in a template with a template tag, e.g.\n *\n * ```django\n * {% all_cookie_groups 'cookie-consent__cookie-groups' %}\n * ```\n *\n * resulting in the selector: `'#cookie-consent__cookie-groups'`.\n */\n cookieGroupsSelector: string;\n acceptSelector: string;\n declineSelector: string;\n /**\n * Either a string (selector), DOMNode or null.\n *\n * If null, the bar is appended to the body. If provided, the node is used or looked\n * up.\n */\n insertBefore: string | HTMLElement | null;\n /**\n * Optional callback for when the cookie bar is being shown.\n *\n * You can use this to add a CSS class name to the body, for example.\n */\n onShow?: () => void;\n /**\n * Optional callback called when cookies are accepted.\n */\n onAccept?: (acceptedGroups: CookieGroup[], event?: MouseEvent) => void;\n /**\n * Optional callback called when cookies are accepted.\n */\n onDecline?: (declinedGroups: CookieGroup[], event?: MouseEvent) => void;\n /**\n * Name of the header to use for the CSRF token.\n *\n * If needed, this can be read/set via `settings.CSRF_HEADER_NAME` in the backend.\n */\n csrfHeaderName: string;\n};\n\nexport interface CookieStatus {\n csrftoken: string;\n /**\n * Backend endpoint to POST to to accept the cookie groups.\n */\n acceptUrl: string;\n /**\n * Backend endpoint to POST to to decline the cookie groups.\n */\n declineUrl: string;\n /**\n * Array of accepted cookie group varnames.\n */\n acceptedCookieGroups: string[];\n /**\n * Array of declined cookie group varnames.\n */\n declinedCookieGroups: string[];\n /**\n * Array of undecided cookie group varnames.\n */\n notAcceptedOrDeclinedCookieGroups: string[];\n}\n\nconst DEFAULT_FETCH_HEADERS: Record<string, string> = {\n 'X-Cookie-Consent-Fetch': '1'\n};\n\nclass FetchClient {\n protected statusUrl: string;\n protected csrfHeaderName: string;\n protected cookieStatus: CookieStatus | null;\n\n constructor(statusUrl: string, csrfHeaderName: string) {\n this.statusUrl = statusUrl;\n this.csrfHeaderName = csrfHeaderName;\n this.cookieStatus = null;\n }\n\n async getCookieStatus(): Promise<CookieStatus> {\n if (this.cookieStatus === null) {\n const response = await window.fetch(\n this.statusUrl,\n {\n method: 'GET',\n credentials: 'same-origin',\n headers: DEFAULT_FETCH_HEADERS,\n }\n );\n this.cookieStatus = await response.json();\n }\n\n // type checker sanity check\n if (this.cookieStatus === null) {\n throw new Error('Unexpectedly received null cookie status');\n }\n return this.cookieStatus;\n };\n\n async saveCookiesStatusBackend (urlProperty: 'acceptUrl' | 'declineUrl') {\n const cookieStatus = await this.getCookieStatus();\n const url = cookieStatus[urlProperty];\n if (!url) {\n throw new Error(`Missing url for ${urlProperty} - was the cookie status not loaded properly?`);\n }\n\n await window.fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n ...DEFAULT_FETCH_HEADERS,\n [this.csrfHeaderName]: cookieStatus.csrftoken\n }\n });\n }\n}\n\n/**\n * Read the JSON script node contents and parse the content as JSON.\n *\n * The result is the list of available/configured cookie groups.\n * Use the status URL to get the accepted/declined status for an individual user.\n */\nexport const loadCookieGroups = (selector: string): CookieGroup[] => {\n const node = document.querySelector<HTMLScriptElement>(selector);\n if (!node) {\n throw new Error(`No cookie groups (script) tag found, using selector: '${selector}'`);\n }\n return JSON.parse(node.innerText);\n};\n\nconst doInsertBefore = (beforeNode: HTMLElement, newNode: Node): void => {\n const parent = beforeNode.parentNode;\n if (parent === null) throw new Error('Reference node doesn\\'t have a parent.');\n parent.insertBefore(newNode, beforeNode);\n}\n\ntype RegisterEventsOptions = Pick<\n Options,\n 'acceptSelector' | 'onAccept' | 'declineSelector' | 'onDecline'\n> & Pick<\n CookieStatus,\n 'acceptedCookieGroups' | 'declinedCookieGroups' | 'notAcceptedOrDeclinedCookieGroups'\n> & {\n client: FetchClient,\n cookieBarNode: Element;\n cookieGroups: CookieGroup[];\n}\n\n/**\n * Register the accept/decline event handlers.\n *\n * Note that we can't just set the decline or accept cookie purely client-side, as the\n * cookie possibly has the httpOnly flag set.\n */\nconst registerEvents = ({\n client,\n cookieBarNode,\n cookieGroups,\n acceptSelector,\n onAccept,\n declineSelector,\n onDecline,\n acceptedCookieGroups: accepted,\n declinedCookieGroups: declined,\n notAcceptedOrDeclinedCookieGroups: undecided,\n}: RegisterEventsOptions): void => {\n\n const acceptNode = cookieBarNode.querySelector<HTMLElement>(acceptSelector);\n if (acceptNode) {\n acceptNode.addEventListener('click', event => {\n event.preventDefault();\n const acceptedGroups = filterCookieGroups(cookieGroups, accepted.concat(undecided));\n onAccept?.(acceptedGroups, event);\n // trigger async action, but don't wait for completion\n client.saveCookiesStatusBackend('acceptUrl');\n cookieBarNode.parentNode!.removeChild(cookieBarNode);\n });\n }\n\n const declineNode = cookieBarNode.querySelector<HTMLElement>(declineSelector);\n if (declineNode) {\n declineNode.addEventListener('click', event => {\n event.preventDefault();\n const declinedGroups = filterCookieGroups(cookieGroups, declined.concat(undecided));\n onDecline?.(declinedGroups, event);\n // trigger async action, but don't wait for completion\n client.saveCookiesStatusBackend('declineUrl');\n cookieBarNode.parentNode!.removeChild(cookieBarNode);\n });\n }\n};\n\n/**\n * Filter the cookie groups down to a subset of specified varnames.\n */\nconst filterCookieGroups = (cookieGroups: CookieGroup[], varNames: string[]) => {\n return cookieGroups.filter(group => varNames.includes(group.varname));\n};\n\n// See https://github.com/microsoft/TypeScript/issues/283\nfunction cloneNode<T extends Node>(node: T) {\n return <T>node.cloneNode(true);\n}\n\nexport const showCookieBar = async (options: Partial<Options> = {}): Promise<void> => {\n const {\n templateSelector = '#cookie-consent__cookie-bar',\n cookieGroupsSelector = '#cookie-consent__cookie-groups',\n acceptSelector = '.cookie-consent__accept',\n declineSelector = '.cookie-consent__decline',\n insertBefore = null,\n onShow,\n onAccept,\n onDecline,\n statusUrl = '',\n csrfHeaderName = 'X-CSRFToken', // Django's default, can be overridden with settings.CSRF_HEADER_NAME\n } = options;\n\n const cookieGroups = loadCookieGroups(cookieGroupsSelector);\n\n // no cookie groups -> abort, nothing to do\n if (!cookieGroups.length) return;\n\n const templateNode = document.querySelector<HTMLTemplateElement>(templateSelector);\n if (!templateNode) {\n throw new Error(`No (template) element found for selector '${templateSelector}'.`)\n }\n\n // insert before a given node, if specified, or append to the body as default behaviour\n const doInsert = insertBefore === null\n ? (cookieBarNode: Node) => document.querySelector('body')!.appendChild(cookieBarNode)\n : typeof insertBefore === 'string'\n ? (cookieBarNode: Node) => {\n const referenceNode = document.querySelector<HTMLElement>(insertBefore);\n if (referenceNode === null) throw new Error(`No element found for selector '${insertBefore}'.`)\n doInsertBefore(referenceNode, cookieBarNode);\n }\n : (cookieBarNode: Node) => doInsertBefore(insertBefore, cookieBarNode)\n ;\n\n if (!statusUrl) throw new Error('Missing status URL option, did you forget to pass the `statusUrl` option?');\n\n const client = new FetchClient(statusUrl, csrfHeaderName);\n const cookieStatus = await client.getCookieStatus();\n\n // calculate the cookie groups to invoke the callbacks. We deliberately fire those\n // without awaiting so that our cookie bar is shown/hidden as soon as possible.\n const {\n acceptedCookieGroups,\n declinedCookieGroups,\n notAcceptedOrDeclinedCookieGroups\n } = cookieStatus;\n\n const acceptedGroups = filterCookieGroups(cookieGroups, acceptedCookieGroups);\n if (acceptedGroups.length) onAccept?.(acceptedGroups);\n const declinedGroups = filterCookieGroups(cookieGroups, declinedCookieGroups);\n if (declinedGroups.length) onDecline?.(declinedGroups);\n\n // there are no (more) cookie groups to accept, don't show the bar\n if (!notAcceptedOrDeclinedCookieGroups.length) return;\n\n // grab the contents from the template node and add them to the DOM, optionally\n // calling the onShow callback\n const childToClone = templateNode.content.firstElementChild;\n if (childToClone === null) throw new Error('The cookie bar template element may not be empty.');\n const cookieBarNode = cloneNode(childToClone);\n registerEvents({\n client,\n cookieBarNode,\n cookieGroups,\n acceptSelector,\n onAccept,\n declineSelector,\n onDecline,\n acceptedCookieGroups,\n declinedCookieGroups,\n notAcceptedOrDeclinedCookieGroups,\n });\n doInsert(cookieBarNode);\n onShow?.();\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["cookieBarNode"]
|
|
7
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
from django import template
|
|
1
|
+
import warnings
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from django.core.urlresolvers import reverse
|
|
3
|
+
from django import template
|
|
4
|
+
from django.urls import reverse
|
|
5
|
+
from django.utils.html import json_script
|
|
8
6
|
|
|
9
|
-
from
|
|
10
|
-
from
|
|
7
|
+
from ..cache import all_cookie_groups as get_all_cookie_groups
|
|
8
|
+
from ..conf import settings
|
|
9
|
+
from ..util import (
|
|
11
10
|
are_all_cookies_accepted,
|
|
12
11
|
get_accepted_cookies,
|
|
13
12
|
get_cookie_dict_from_request,
|
|
@@ -90,10 +89,15 @@ def cookie_consent_decline_url(cookie_groups):
|
|
|
90
89
|
|
|
91
90
|
|
|
92
91
|
@register.simple_tag
|
|
93
|
-
def get_accept_cookie_groups_cookie_string(request, cookie_groups):
|
|
92
|
+
def get_accept_cookie_groups_cookie_string(request, cookie_groups): # pragma: no cover
|
|
94
93
|
"""
|
|
95
94
|
Tag returns accept cookie string suitable to use in javascript.
|
|
96
95
|
"""
|
|
96
|
+
warnings.warn(
|
|
97
|
+
"Cookie string template tags for JS are deprecated and will be removed "
|
|
98
|
+
"in django-cookie-consent 1.0",
|
|
99
|
+
DeprecationWarning,
|
|
100
|
+
)
|
|
97
101
|
cookie_dic = get_cookie_dict_from_request(request)
|
|
98
102
|
for cookie_group in cookie_groups:
|
|
99
103
|
cookie_dic[cookie_group.varname] = cookie_group.get_version()
|
|
@@ -105,6 +109,11 @@ def get_decline_cookie_groups_cookie_string(request, cookie_groups):
|
|
|
105
109
|
"""
|
|
106
110
|
Tag returns decline cookie string suitable to use in javascript.
|
|
107
111
|
"""
|
|
112
|
+
warnings.warn(
|
|
113
|
+
"Cookie string template tags for JS are deprecated and will be removed "
|
|
114
|
+
"in django-cookie-consent 1.0",
|
|
115
|
+
DeprecationWarning,
|
|
116
|
+
)
|
|
108
117
|
cookie_dic = get_cookie_dict_from_request(request)
|
|
109
118
|
for cookie_group in cookie_groups:
|
|
110
119
|
cookie_dic[cookie_group.varname] = settings.COOKIE_CONSENT_DECLINE
|
|
@@ -124,6 +133,13 @@ def js_type_for_cookie_consent(request, varname, cookie=None):
|
|
|
124
133
|
alert("Social cookie accepted");
|
|
125
134
|
</script>
|
|
126
135
|
"""
|
|
136
|
+
# This approach doesn't work with page caches and/or strict Content-Security-Policies
|
|
137
|
+
# (unless you use nonces, which again doesn't work with aggressive page caching).
|
|
138
|
+
warnings.warn(
|
|
139
|
+
"Template tags for use in/with JS are deprecated and will be removed "
|
|
140
|
+
"in django-cookie-consent 1.0",
|
|
141
|
+
DeprecationWarning,
|
|
142
|
+
)
|
|
127
143
|
enabled = is_cookie_consent_enabled(request)
|
|
128
144
|
if not enabled:
|
|
129
145
|
res = True
|
|
@@ -147,3 +163,17 @@ def accepted_cookies(request):
|
|
|
147
163
|
|
|
148
164
|
"""
|
|
149
165
|
return [c.varname for c in get_accepted_cookies(request)]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@register.simple_tag
|
|
169
|
+
def all_cookie_groups(element_id: str):
|
|
170
|
+
"""
|
|
171
|
+
Serialize all cookie groups to JSON and output them in a script tag.
|
|
172
|
+
|
|
173
|
+
:param element_id: The ID for the script tag so you can look it up in JS later.
|
|
174
|
+
|
|
175
|
+
This uses Django's core json_script filter under the hood.
|
|
176
|
+
"""
|
|
177
|
+
groups = get_all_cookie_groups()
|
|
178
|
+
value = [group.for_json() for group in groups.values()]
|
|
179
|
+
return json_script(value, element_id)
|