django-cookie-consent 0.8.0__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
- cookie_consent/__init__.py +1 -1
- cookie_consent/admin.py +32 -4
- cookie_consent/cache.py +13 -8
- cookie_consent/conf.py +21 -13
- cookie_consent/forms.py +50 -0
- cookie_consent/middleware.py +7 -6
- cookie_consent/migrations/0001_initial.py +2 -1
- cookie_consent/migrations/0003_alter_cookiegroup_varname.py +2 -2
- cookie_consent/migrations/0004_cookie_natural_key.py +0 -1
- cookie_consent/models.py +30 -20
- cookie_consent/processor.py +77 -0
- cookie_consent/py.typed +0 -0
- cookie_consent/static/cookie_consent/cookiebar.module.js +8 -3
- cookie_consent/static/cookie_consent/cookiebar.module.js.map +2 -2
- cookie_consent/templates/cookie_consent/_cookie_group.html +4 -2
- cookie_consent/templatetags/__init__.py +0 -1
- cookie_consent/templatetags/cookie_consent_tags.py +25 -116
- cookie_consent/urls.py +3 -25
- cookie_consent/util.py +87 -119
- cookie_consent/views.py +46 -40
- django_cookie_consent-1.0.0.dist-info/METADATA +96 -0
- django_cookie_consent-1.0.0.dist-info/RECORD +31 -0
- {django_cookie_consent-0.8.0.dist-info → django_cookie_consent-1.0.0.dist-info}/WHEEL +1 -1
- cookie_consent/static/cookie_consent/cookiebar.js +0 -67
- django_cookie_consent-0.8.0.dist-info/METADATA +0 -125
- django_cookie_consent-0.8.0.dist-info/RECORD +0 -30
- django_cookie_consent-0.8.0.dist-info/licenses/AUTHORS +0 -14
- {django_cookie_consent-0.8.0.dist-info → django_cookie_consent-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {django_cookie_consent-0.8.0.dist-info → django_cookie_consent-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
from collections.abc import Collection
|
|
2
2
|
|
|
3
3
|
from django import template
|
|
4
|
-
from django.
|
|
4
|
+
from django.http import HttpRequest
|
|
5
5
|
from django.utils.html import json_script
|
|
6
6
|
|
|
7
7
|
from ..cache import all_cookie_groups as get_all_cookie_groups
|
|
8
|
-
from ..
|
|
8
|
+
from ..models import CookieGroup
|
|
9
9
|
from ..util import (
|
|
10
10
|
are_all_cookies_accepted,
|
|
11
|
-
get_accepted_cookies,
|
|
12
|
-
get_cookie_dict_from_request,
|
|
13
|
-
get_cookie_string,
|
|
14
11
|
get_cookie_value_from_request,
|
|
15
12
|
get_not_accepted_or_declined_cookie_groups,
|
|
16
13
|
is_cookie_consent_enabled,
|
|
@@ -20,31 +17,39 @@ register = template.Library()
|
|
|
20
17
|
|
|
21
18
|
|
|
22
19
|
@register.filter
|
|
23
|
-
def cookie_group_accepted(request,
|
|
20
|
+
def cookie_group_accepted(request: HttpRequest, group_or_cookie: str) -> bool:
|
|
24
21
|
"""
|
|
25
|
-
|
|
22
|
+
Return ``True`` if the cookie group/cookie is accepted.
|
|
26
23
|
|
|
27
24
|
Examples:
|
|
28
|
-
|
|
25
|
+
|
|
26
|
+
.. code-block:: django
|
|
29
27
|
|
|
30
28
|
{{ request|cookie_group_accepted:"analytics" }}
|
|
31
29
|
{{ request|cookie_group_accepted:"analytics=*:.google.com" }}
|
|
32
30
|
"""
|
|
33
|
-
value = get_cookie_value_from_request(request, *
|
|
31
|
+
value = get_cookie_value_from_request(request, *group_or_cookie.split("="))
|
|
34
32
|
return value is True
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
@register.filter
|
|
38
|
-
def cookie_group_declined(request,
|
|
36
|
+
def cookie_group_declined(request: HttpRequest, group_or_cookie: str) -> bool:
|
|
39
37
|
"""
|
|
40
|
-
|
|
38
|
+
Return ``True`` if the cookie group/cookie is declined.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
|
|
42
|
+
.. code-block:: django
|
|
43
|
+
|
|
44
|
+
{{ request|cookie_group_declined:"analytics" }}
|
|
45
|
+
{{ request|cookie_group_declined:"analytics=*:.google.com" }}
|
|
41
46
|
"""
|
|
42
|
-
value = get_cookie_value_from_request(request, *
|
|
47
|
+
value = get_cookie_value_from_request(request, *group_or_cookie.split("="))
|
|
43
48
|
return value is False
|
|
44
49
|
|
|
45
50
|
|
|
46
51
|
@register.filter
|
|
47
|
-
def all_cookies_accepted(request):
|
|
52
|
+
def all_cookies_accepted(request: HttpRequest) -> bool:
|
|
48
53
|
"""
|
|
49
54
|
Filter returns if all cookies are accepted.
|
|
50
55
|
"""
|
|
@@ -52,119 +57,23 @@ def all_cookies_accepted(request):
|
|
|
52
57
|
|
|
53
58
|
|
|
54
59
|
@register.simple_tag
|
|
55
|
-
def not_accepted_or_declined_cookie_groups(
|
|
60
|
+
def not_accepted_or_declined_cookie_groups(
|
|
61
|
+
request: HttpRequest,
|
|
62
|
+
) -> Collection[CookieGroup]:
|
|
56
63
|
"""
|
|
57
|
-
|
|
58
|
-
or decline.
|
|
64
|
+
Return the cookie groups for which no explicit accept or decline has been given.
|
|
59
65
|
"""
|
|
60
66
|
return get_not_accepted_or_declined_cookie_groups(request)
|
|
61
67
|
|
|
62
68
|
|
|
63
69
|
@register.filter
|
|
64
|
-
def cookie_consent_enabled(request):
|
|
70
|
+
def cookie_consent_enabled(request: HttpRequest) -> bool:
|
|
65
71
|
"""
|
|
66
|
-
|
|
72
|
+
Indicate whether the cookie-consent app is enabled or not.
|
|
67
73
|
"""
|
|
68
74
|
return is_cookie_consent_enabled(request)
|
|
69
75
|
|
|
70
76
|
|
|
71
|
-
@register.simple_tag
|
|
72
|
-
def cookie_consent_accept_url(cookie_groups):
|
|
73
|
-
"""
|
|
74
|
-
Assignement tag returns url for accepting given concept groups.
|
|
75
|
-
"""
|
|
76
|
-
varnames = ",".join([g.varname for g in cookie_groups])
|
|
77
|
-
url = reverse("cookie_consent_accept", kwargs={"varname": varnames})
|
|
78
|
-
return url
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@register.simple_tag
|
|
82
|
-
def cookie_consent_decline_url(cookie_groups):
|
|
83
|
-
"""
|
|
84
|
-
Assignement tag returns url for declining given concept groups.
|
|
85
|
-
"""
|
|
86
|
-
varnames = ",".join([g.varname for g in cookie_groups])
|
|
87
|
-
url = reverse("cookie_consent_decline", kwargs={"varname": varnames})
|
|
88
|
-
return url
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@register.simple_tag
|
|
92
|
-
def get_accept_cookie_groups_cookie_string(request, cookie_groups): # pragma: no cover
|
|
93
|
-
"""
|
|
94
|
-
Tag returns accept cookie string suitable to use in javascript.
|
|
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
|
-
)
|
|
101
|
-
cookie_dic = get_cookie_dict_from_request(request)
|
|
102
|
-
for cookie_group in cookie_groups:
|
|
103
|
-
cookie_dic[cookie_group.varname] = cookie_group.get_version()
|
|
104
|
-
return get_cookie_string(cookie_dic)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@register.simple_tag
|
|
108
|
-
def get_decline_cookie_groups_cookie_string(request, cookie_groups):
|
|
109
|
-
"""
|
|
110
|
-
Tag returns decline cookie string suitable to use in javascript.
|
|
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
|
-
)
|
|
117
|
-
cookie_dic = get_cookie_dict_from_request(request)
|
|
118
|
-
for cookie_group in cookie_groups:
|
|
119
|
-
cookie_dic[cookie_group.varname] = settings.COOKIE_CONSENT_DECLINE
|
|
120
|
-
return get_cookie_string(cookie_dic)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@register.simple_tag
|
|
124
|
-
def js_type_for_cookie_consent(request, varname, cookie=None):
|
|
125
|
-
"""
|
|
126
|
-
Tag returns "x/cookie_consent" when processing javascript
|
|
127
|
-
will create an cookie and consent does not exists yet.
|
|
128
|
-
|
|
129
|
-
Example::
|
|
130
|
-
|
|
131
|
-
<script type="{% js_type_for_cookie_consent request "social" %}"
|
|
132
|
-
data-varname="social">
|
|
133
|
-
alert("Social cookie accepted");
|
|
134
|
-
</script>
|
|
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
|
-
)
|
|
143
|
-
enabled = is_cookie_consent_enabled(request)
|
|
144
|
-
if not enabled:
|
|
145
|
-
res = True
|
|
146
|
-
else:
|
|
147
|
-
value = get_cookie_value_from_request(request, varname, cookie)
|
|
148
|
-
if value is None:
|
|
149
|
-
res = settings.COOKIE_CONSENT_OPT_OUT
|
|
150
|
-
else:
|
|
151
|
-
res = value
|
|
152
|
-
return "text/javascript" if res else "x/cookie_consent"
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
@register.filter
|
|
156
|
-
def accepted_cookies(request):
|
|
157
|
-
"""
|
|
158
|
-
Filter returns accepted cookies varnames.
|
|
159
|
-
|
|
160
|
-
.. code-block:: django
|
|
161
|
-
|
|
162
|
-
{{ request|accepted_cookies }}
|
|
163
|
-
|
|
164
|
-
"""
|
|
165
|
-
return [c.varname for c in get_accepted_cookies(request)]
|
|
166
|
-
|
|
167
|
-
|
|
168
77
|
@register.simple_tag
|
|
169
78
|
def all_cookie_groups(element_id: str):
|
|
170
79
|
"""
|
cookie_consent/urls.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
from django.urls import path, re_path
|
|
3
|
-
from django.views.decorators.csrf import csrf_exempt
|
|
1
|
+
from django.urls import path
|
|
4
2
|
|
|
5
3
|
from .views import (
|
|
6
4
|
CookieGroupAcceptView,
|
|
@@ -10,28 +8,8 @@ from .views import (
|
|
|
10
8
|
)
|
|
11
9
|
|
|
12
10
|
urlpatterns = [
|
|
13
|
-
path(
|
|
14
|
-
|
|
15
|
-
csrf_exempt(CookieGroupAcceptView.as_view()),
|
|
16
|
-
name="cookie_consent_accept_all",
|
|
17
|
-
),
|
|
18
|
-
# TODO: use form or query string params for this instead?
|
|
19
|
-
re_path(
|
|
20
|
-
r"^accept/(?P<varname>.*)/$",
|
|
21
|
-
csrf_exempt(CookieGroupAcceptView.as_view()),
|
|
22
|
-
name="cookie_consent_accept",
|
|
23
|
-
),
|
|
24
|
-
# TODO: use form or query string params for this instead?
|
|
25
|
-
re_path(
|
|
26
|
-
r"^decline/(?P<varname>.*)/$",
|
|
27
|
-
csrf_exempt(CookieGroupDeclineView.as_view()),
|
|
28
|
-
name="cookie_consent_decline",
|
|
29
|
-
),
|
|
30
|
-
path(
|
|
31
|
-
"decline/",
|
|
32
|
-
csrf_exempt(CookieGroupDeclineView.as_view()),
|
|
33
|
-
name="cookie_consent_decline_all",
|
|
34
|
-
),
|
|
11
|
+
path("accept/", CookieGroupAcceptView.as_view(), name="cookie_consent_accept"),
|
|
12
|
+
path("decline/", CookieGroupDeclineView.as_view(), name="cookie_consent_decline"),
|
|
35
13
|
path("status/", CookieStatusView.as_view(), name="cookie_consent_status"),
|
|
36
14
|
path("", CookieGroupListView.as_view(), name="cookie_consent_cookie_group_list"),
|
|
37
15
|
]
|
cookie_consent/util.py
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from collections.abc import Callable, Collection, Iterator
|
|
3
|
+
|
|
4
|
+
from django.http import HttpRequest, HttpResponseBase
|
|
4
5
|
|
|
5
6
|
from .cache import all_cookie_groups, get_cookie, get_cookie_group
|
|
6
7
|
from .conf import settings
|
|
7
|
-
from .models import
|
|
8
|
+
from .models import Cookie, CookieGroup
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
COOKIE_GROUP_SEP = "|"
|
|
13
|
+
KEY_VALUE_SEP = "="
|
|
8
14
|
|
|
9
15
|
|
|
10
|
-
def parse_cookie_str(cookie):
|
|
11
|
-
dic = {}
|
|
16
|
+
def parse_cookie_str(cookie: str) -> dict[str, str]:
|
|
12
17
|
if not cookie:
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
return {}
|
|
19
|
+
|
|
20
|
+
bits = cookie.split(COOKIE_GROUP_SEP)
|
|
21
|
+
|
|
22
|
+
def _gen_pairs() -> Iterator[tuple[str, str]]:
|
|
23
|
+
for possible_pair in bits:
|
|
24
|
+
parts = possible_pair.split(KEY_VALUE_SEP)
|
|
25
|
+
if len(parts) == 2:
|
|
26
|
+
varname, cookie = parts
|
|
27
|
+
yield varname, cookie
|
|
28
|
+
else:
|
|
29
|
+
logger.debug("cookie_value_discarded", extra={"value": possible_pair})
|
|
18
30
|
|
|
31
|
+
return dict(_gen_pairs())
|
|
19
32
|
|
|
20
|
-
def dict_to_cookie_str(dic):
|
|
21
|
-
return "|".join(["%s=%s" % (k, v) for k, v in dic.items() if v])
|
|
22
33
|
|
|
34
|
+
def _contains_invalid_characters(*inputs: str) -> bool:
|
|
35
|
+
# = and | are special separators. They are unexpected characters in both
|
|
36
|
+
# keys and values.
|
|
37
|
+
for separator in (COOKIE_GROUP_SEP, KEY_VALUE_SEP):
|
|
38
|
+
for value in inputs:
|
|
39
|
+
if separator in value:
|
|
40
|
+
logger.debug("skip_separator", extra={"value": value, "sep": separator})
|
|
41
|
+
return True
|
|
42
|
+
return False
|
|
23
43
|
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
|
|
45
|
+
def dict_to_cookie_str(dic: dict[str, str]) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Serialize a dictionary of cookie-group metadata to a string.
|
|
48
|
+
|
|
49
|
+
The result is stored in a cookie itself. Note that the dictionary keys are expected
|
|
50
|
+
to be cookie group ``varname`` fields, which are validated against a slug regex. The
|
|
51
|
+
values are supposed to be ISO-8601 timestamps.
|
|
52
|
+
|
|
53
|
+
Invalid key/value pairs are dropped.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def _gen_pairs() -> Iterator[str]:
|
|
57
|
+
for key, value in dic.items():
|
|
58
|
+
if _contains_invalid_characters(key, value):
|
|
59
|
+
continue
|
|
60
|
+
yield f"{key}={value}"
|
|
61
|
+
|
|
62
|
+
return "|".join(_gen_pairs())
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_cookie_dict_from_request(request: HttpRequest) -> dict[str, str]:
|
|
66
|
+
cookie_str = request.COOKIES.get(settings.COOKIE_CONSENT_NAME, "")
|
|
26
67
|
return parse_cookie_str(cookie_str)
|
|
27
68
|
|
|
28
69
|
|
|
29
|
-
def set_cookie_dict_to_response(
|
|
70
|
+
def set_cookie_dict_to_response(
|
|
71
|
+
response: HttpResponseBase, dic: dict[str, str]
|
|
72
|
+
) -> None:
|
|
30
73
|
response.set_cookie(
|
|
31
74
|
settings.COOKIE_CONSENT_NAME,
|
|
32
75
|
dict_to_cookie_str(dic),
|
|
33
76
|
max_age=settings.COOKIE_CONSENT_MAX_AGE,
|
|
34
77
|
domain=settings.COOKIE_CONSENT_DOMAIN,
|
|
35
|
-
secure=settings.COOKIE_CONSENT_SECURE
|
|
36
|
-
httponly=settings.COOKIE_CONSENT_HTTPONLY
|
|
78
|
+
secure=settings.COOKIE_CONSENT_SECURE,
|
|
79
|
+
httponly=settings.COOKIE_CONSENT_HTTPONLY,
|
|
37
80
|
samesite=settings.COOKIE_CONSENT_SAMESITE,
|
|
38
81
|
)
|
|
39
82
|
|
|
40
83
|
|
|
41
|
-
def get_cookie_value_from_request(
|
|
84
|
+
def get_cookie_value_from_request(
|
|
85
|
+
request: HttpRequest, varname: str, cookie: str = ""
|
|
86
|
+
) -> bool | None:
|
|
42
87
|
"""
|
|
43
88
|
Returns if cookie group or its specific cookie has been accepted.
|
|
44
89
|
|
|
45
90
|
Returns True or False when cookie is accepted or declined or None
|
|
46
91
|
if cookie is not set.
|
|
47
92
|
"""
|
|
48
|
-
cookie_dic
|
|
49
|
-
if not cookie_dic:
|
|
93
|
+
if not (cookie_dic := get_cookie_dict_from_request(request)):
|
|
50
94
|
return None
|
|
51
|
-
|
|
52
|
-
cookie_group = get_cookie_group(varname=varname)
|
|
53
|
-
if not cookie_group:
|
|
95
|
+
if not (cookie_group := get_cookie_group(varname=varname)):
|
|
54
96
|
return None
|
|
97
|
+
|
|
98
|
+
_cookie: Cookie | None = None
|
|
55
99
|
if cookie:
|
|
56
100
|
name, domain = cookie.split(":")
|
|
57
|
-
|
|
58
|
-
else:
|
|
59
|
-
cookie = None
|
|
101
|
+
_cookie = get_cookie(cookie_group, name, domain)
|
|
60
102
|
|
|
61
|
-
version
|
|
103
|
+
match version := cookie_dic.get(varname, None):
|
|
104
|
+
case None:
|
|
105
|
+
return None
|
|
106
|
+
case str() if version == settings.COOKIE_CONSENT_DECLINE:
|
|
107
|
+
return False
|
|
62
108
|
|
|
63
|
-
if
|
|
64
|
-
|
|
65
|
-
if version is None:
|
|
66
|
-
return None
|
|
67
|
-
if not cookie:
|
|
68
|
-
v = cookie_group.get_version()
|
|
69
|
-
else:
|
|
70
|
-
v = cookie.get_version()
|
|
71
|
-
if version >= v:
|
|
109
|
+
reference_version = _cookie.get_version() if _cookie else cookie_group.get_version()
|
|
110
|
+
if version >= reference_version:
|
|
72
111
|
return True
|
|
73
112
|
return None
|
|
74
113
|
|
|
75
114
|
|
|
76
|
-
def get_cookie_groups(varname=
|
|
115
|
+
def get_cookie_groups(varname: str = "") -> Collection[CookieGroup]:
|
|
77
116
|
if not varname:
|
|
78
117
|
return all_cookie_groups().values()
|
|
79
118
|
keys = varname.split(",")
|
|
80
119
|
return [g for k, g in all_cookie_groups().items() if k in keys]
|
|
81
120
|
|
|
82
121
|
|
|
83
|
-
def
|
|
84
|
-
"""
|
|
85
|
-
Accept cookies in Cookie Group specified by ``varname``.
|
|
86
|
-
"""
|
|
87
|
-
cookie_dic = get_cookie_dict_from_request(request)
|
|
88
|
-
for cookie_group in get_cookie_groups(varname):
|
|
89
|
-
cookie_dic[cookie_group.varname] = cookie_group.get_version()
|
|
90
|
-
if settings.COOKIE_CONSENT_LOG_ENABLED:
|
|
91
|
-
LogItem.objects.create(
|
|
92
|
-
action=ACTION_ACCEPTED,
|
|
93
|
-
cookiegroup=cookie_group,
|
|
94
|
-
version=cookie_group.get_version(),
|
|
95
|
-
)
|
|
96
|
-
set_cookie_dict_to_response(response, cookie_dic)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def delete_cookies(response, cookie_group):
|
|
100
|
-
if cookie_group.is_deletable:
|
|
101
|
-
for cookie in cookie_group.cookie_set.all():
|
|
102
|
-
response.delete_cookie(cookie.name, cookie.path, cookie.domain)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def decline_cookies(request, response, varname=None):
|
|
106
|
-
"""
|
|
107
|
-
Decline and delete cookies in CookieGroup specified by ``varname``.
|
|
108
|
-
"""
|
|
109
|
-
cookie_dic = get_cookie_dict_from_request(request)
|
|
110
|
-
for cookie_group in get_cookie_groups(varname):
|
|
111
|
-
cookie_dic[cookie_group.varname] = settings.COOKIE_CONSENT_DECLINE
|
|
112
|
-
delete_cookies(response, cookie_group)
|
|
113
|
-
if settings.COOKIE_CONSENT_LOG_ENABLED:
|
|
114
|
-
LogItem.objects.create(
|
|
115
|
-
action=ACTION_DECLINED,
|
|
116
|
-
cookiegroup=cookie_group,
|
|
117
|
-
version=cookie_group.get_version(),
|
|
118
|
-
)
|
|
119
|
-
set_cookie_dict_to_response(response, cookie_dic)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def are_all_cookies_accepted(request):
|
|
122
|
+
def are_all_cookies_accepted(request: HttpRequest) -> bool:
|
|
123
123
|
"""
|
|
124
124
|
Returns if all cookies are accepted.
|
|
125
125
|
"""
|
|
@@ -131,7 +131,7 @@ def are_all_cookies_accepted(request):
|
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def _get_cookie_groups_by_state(request, state:
|
|
134
|
+
def _get_cookie_groups_by_state(request, state: bool | None) -> Collection[CookieGroup]:
|
|
135
135
|
return [
|
|
136
136
|
cookie_group
|
|
137
137
|
for cookie_group in get_cookie_groups()
|
|
@@ -139,64 +139,32 @@ def _get_cookie_groups_by_state(request, state: Union[bool, None]):
|
|
|
139
139
|
]
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
def get_not_accepted_or_declined_cookie_groups(
|
|
142
|
+
def get_not_accepted_or_declined_cookie_groups(
|
|
143
|
+
request: HttpRequest,
|
|
144
|
+
) -> Collection[CookieGroup]:
|
|
143
145
|
"""
|
|
144
146
|
Returns all cookie groups that are neither accepted or declined.
|
|
145
147
|
"""
|
|
146
148
|
return _get_cookie_groups_by_state(request, state=None)
|
|
147
149
|
|
|
148
150
|
|
|
149
|
-
def get_accepted_cookie_groups(request):
|
|
151
|
+
def get_accepted_cookie_groups(request: HttpRequest) -> Collection[CookieGroup]:
|
|
150
152
|
"""
|
|
151
153
|
Returns all cookie groups that are accepted.
|
|
152
154
|
"""
|
|
153
155
|
return _get_cookie_groups_by_state(request, state=True)
|
|
154
156
|
|
|
155
157
|
|
|
156
|
-
def get_declined_cookie_groups(request):
|
|
158
|
+
def get_declined_cookie_groups(request: HttpRequest) -> Collection[CookieGroup]:
|
|
157
159
|
"""
|
|
158
160
|
Returns all cookie groups that are declined.
|
|
159
161
|
"""
|
|
160
162
|
return _get_cookie_groups_by_state(request, state=False)
|
|
161
163
|
|
|
162
164
|
|
|
163
|
-
def is_cookie_consent_enabled(request):
|
|
165
|
+
def is_cookie_consent_enabled(request: HttpRequest) -> bool:
|
|
164
166
|
"""
|
|
165
167
|
Returns if django-cookie-consent is enabled for given request.
|
|
166
168
|
"""
|
|
167
|
-
enabled = settings.COOKIE_CONSENT_ENABLED
|
|
168
|
-
if callable(enabled)
|
|
169
|
-
return enabled(request)
|
|
170
|
-
else:
|
|
171
|
-
return enabled
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def get_cookie_string(cookie_dic):
|
|
175
|
-
"""
|
|
176
|
-
Returns cookie in format suitable for use in javascript.
|
|
177
|
-
"""
|
|
178
|
-
expires = datetime.datetime.now() + datetime.timedelta(
|
|
179
|
-
seconds=settings.COOKIE_CONSENT_MAX_AGE
|
|
180
|
-
)
|
|
181
|
-
cookie_str = "%s=%s; expires=%s; path=/" % (
|
|
182
|
-
settings.COOKIE_CONSENT_NAME,
|
|
183
|
-
dict_to_cookie_str(cookie_dic),
|
|
184
|
-
expires.strftime("%a, %d %b %Y %H:%M:%S GMT"),
|
|
185
|
-
)
|
|
186
|
-
return cookie_str
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def get_accepted_cookies(request):
|
|
190
|
-
"""
|
|
191
|
-
Returns all accepted cookies.
|
|
192
|
-
"""
|
|
193
|
-
cookie_dic = get_cookie_dict_from_request(request)
|
|
194
|
-
accepted_cookies = []
|
|
195
|
-
for cookie_group in all_cookie_groups().values():
|
|
196
|
-
version = cookie_dic.get(cookie_group.varname, None)
|
|
197
|
-
if not version or version == settings.COOKIE_CONSENT_DECLINE:
|
|
198
|
-
continue
|
|
199
|
-
for cookie in cookie_group.cookie_set.all():
|
|
200
|
-
if version >= cookie.get_version():
|
|
201
|
-
accepted_cookies.append(cookie)
|
|
202
|
-
return accepted_cookies
|
|
169
|
+
enabled: bool | Callable[[HttpRequest], bool] = settings.COOKIE_CONSENT_ENABLED
|
|
170
|
+
return enabled(request) if callable(enabled) else enabled
|
cookie_consent/views.py
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
2
3
|
from django.contrib.auth.views import RedirectURLMixin
|
|
3
|
-
from django.
|
|
4
|
-
|
|
4
|
+
from django.http import (
|
|
5
|
+
HttpRequest,
|
|
6
|
+
HttpResponse,
|
|
7
|
+
HttpResponseBase,
|
|
8
|
+
HttpResponseRedirect,
|
|
9
|
+
JsonResponse,
|
|
10
|
+
)
|
|
5
11
|
from django.middleware.csrf import get_token as get_csrf_token
|
|
6
12
|
from django.urls import reverse
|
|
7
|
-
from django.utils.http import url_has_allowed_host_and_scheme
|
|
8
13
|
from django.views.generic import ListView, View
|
|
9
14
|
|
|
15
|
+
from .conf import settings
|
|
16
|
+
from .forms import ProcessCookiesForm
|
|
10
17
|
from .models import CookieGroup
|
|
18
|
+
from .processor import CookiesProcessor
|
|
11
19
|
from .util import (
|
|
12
|
-
accept_cookies,
|
|
13
|
-
decline_cookies,
|
|
14
20
|
get_accepted_cookie_groups,
|
|
15
21
|
get_declined_cookie_groups,
|
|
16
22
|
get_not_accepted_or_declined_cookie_groups,
|
|
@@ -36,31 +42,40 @@ class CookieGroupListView(ListView):
|
|
|
36
42
|
|
|
37
43
|
|
|
38
44
|
class CookieGroupBaseProcessView(RedirectURLMixin, View):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
"""
|
|
46
|
+
Process the cookie groups submitted in the POST request (or URL parameters).
|
|
47
|
+
|
|
48
|
+
:class:`RedirectURLMixin` takes care of the hardening against open redirects.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
cookie_process_action: Literal["accept", "decline"]
|
|
52
|
+
"""
|
|
53
|
+
Processing action to apply, must be set on the subclasses.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def get_default_redirect_url(self) -> str:
|
|
57
|
+
return settings.COOKIE_CONSENT_SUCCESS_URL
|
|
58
|
+
|
|
59
|
+
def post(self, request: HttpRequest, *args, **kwargs):
|
|
60
|
+
form = ProcessCookiesForm(data=request.POST)
|
|
61
|
+
|
|
62
|
+
if not form.is_valid():
|
|
63
|
+
if is_ajax_like(request):
|
|
64
|
+
return JsonResponse(form.errors.get_json_data())
|
|
65
|
+
else:
|
|
66
|
+
return HttpResponse(form.errors.render())
|
|
67
|
+
|
|
68
|
+
cookie_groups = form.get_cookie_groups()
|
|
69
|
+
|
|
70
|
+
response: HttpResponseBase
|
|
59
71
|
if is_ajax_like(request):
|
|
60
72
|
response = HttpResponse()
|
|
61
73
|
else:
|
|
62
74
|
response = HttpResponseRedirect(self.get_success_url())
|
|
63
|
-
|
|
75
|
+
|
|
76
|
+
processor = CookiesProcessor(request, response)
|
|
77
|
+
processor.process(cookie_groups, action=self.cookie_process_action)
|
|
78
|
+
|
|
64
79
|
return response
|
|
65
80
|
|
|
66
81
|
|
|
@@ -69,8 +84,7 @@ class CookieGroupAcceptView(CookieGroupBaseProcessView):
|
|
|
69
84
|
View to accept CookieGroup.
|
|
70
85
|
"""
|
|
71
86
|
|
|
72
|
-
|
|
73
|
-
accept_cookies(request, response, varname)
|
|
87
|
+
cookie_process_action = "accept"
|
|
74
88
|
|
|
75
89
|
|
|
76
90
|
class CookieGroupDeclineView(CookieGroupBaseProcessView):
|
|
@@ -78,11 +92,7 @@ class CookieGroupDeclineView(CookieGroupBaseProcessView):
|
|
|
78
92
|
View to decline CookieGroup.
|
|
79
93
|
"""
|
|
80
94
|
|
|
81
|
-
|
|
82
|
-
decline_cookies(request, response, varname)
|
|
83
|
-
|
|
84
|
-
def delete(self, request, *args, **kwargs):
|
|
85
|
-
return self.post(request, *args, **kwargs)
|
|
95
|
+
cookie_process_action = "decline"
|
|
86
96
|
|
|
87
97
|
|
|
88
98
|
class CookieStatusView(View):
|
|
@@ -100,14 +110,10 @@ class CookieStatusView(View):
|
|
|
100
110
|
accepted = get_accepted_cookie_groups(request)
|
|
101
111
|
declined = get_declined_cookie_groups(request)
|
|
102
112
|
not_accepted_or_declined = get_not_accepted_or_declined_cookie_groups(request)
|
|
103
|
-
# TODO: change this csv URL param into proper POST params
|
|
104
|
-
varnames = ",".join([group.varname for group in not_accepted_or_declined])
|
|
105
113
|
data = {
|
|
106
114
|
"csrftoken": get_csrf_token(request),
|
|
107
|
-
"acceptUrl": reverse("cookie_consent_accept"
|
|
108
|
-
"declineUrl": reverse(
|
|
109
|
-
"cookie_consent_decline", kwargs={"varname": varnames}
|
|
110
|
-
),
|
|
115
|
+
"acceptUrl": reverse("cookie_consent_accept"),
|
|
116
|
+
"declineUrl": reverse("cookie_consent_decline"),
|
|
111
117
|
"acceptedCookieGroups": [group.varname for group in accepted],
|
|
112
118
|
"declinedCookieGroups": [group.varname for group in declined],
|
|
113
119
|
"notAcceptedOrDeclinedCookieGroups": [
|