django-cookie-consent 0.8.0__tar.gz → 0.9.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.9.0/PKG-INFO +95 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/README.md +12 -13
- django_cookie_consent-0.9.0/cookie_consent/__init__.py +1 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/admin.py +29 -2
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/cache.py +0 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/conf.py +3 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/middleware.py +1 -4
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/migrations/0001_initial.py +2 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/migrations/0003_alter_cookiegroup_varname.py +2 -2
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/migrations/0004_cookie_natural_key.py +0 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/models.py +6 -6
- django_cookie_consent-0.9.0/cookie_consent/templatetags/__init__.py +1 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/templatetags/cookie_consent_tags.py +12 -2
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/urls.py +0 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/util.py +53 -14
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/views.py +2 -2
- django_cookie_consent-0.9.0/django_cookie_consent.egg-info/PKG-INFO +95 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/django_cookie_consent.egg-info/SOURCES.txt +1 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/django_cookie_consent.egg-info/requires.txt +3 -6
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/pyproject.toml +38 -24
- django_cookie_consent-0.9.0/setup.cfg +4 -0
- django_cookie_consent-0.9.0/tests/test_admin.py +24 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_cache.py +0 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_models.py +30 -15
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_templatetags.py +2 -2
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_util.py +24 -1
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_views.py +34 -17
- django_cookie_consent-0.8.0/PKG-INFO +0 -125
- django_cookie_consent-0.8.0/cookie_consent/__init__.py +0 -1
- django_cookie_consent-0.8.0/cookie_consent/templatetags/__init__.py +0 -2
- django_cookie_consent-0.8.0/django_cookie_consent.egg-info/PKG-INFO +0 -125
- django_cookie_consent-0.8.0/setup.cfg +0 -10
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/AUTHORS +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/LICENSE +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/MANIFEST.in +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/apps.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/fixtures/common_cookies.json +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/migrations/0002_auto__add_logitem.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/migrations/__init__.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/static/cookie_consent/cookiebar.js +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/static/cookie_consent/cookiebar.module.js +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/static/cookie_consent/cookiebar.module.js.map +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/templates/cookie_consent/_cookie_group.html +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/templates/cookie_consent/base.html +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/cookie_consent/templates/cookie_consent/cookiegroup_list.html +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/django_cookie_consent.egg-info/dependency_links.txt +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/django_cookie_consent.egg-info/top_level.txt +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_cookie_group_model.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_cookie_model.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_javascript_cookiebar.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_legacy_javascript_cookiebar.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_middleware.py +0 -0
- {django_cookie_consent-0.8.0 → django_cookie_consent-0.9.0}/tests/test_settings.py +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-cookie-consent
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Django cookie consent application
|
|
5
|
+
Author-email: Informatika Mihelac <bmihelac@mihelac.org>
|
|
6
|
+
License-Expression: BSD-2-Clause-first-lines
|
|
7
|
+
Project-URL: Documentation, https://django-cookie-consent.readthedocs.io/en/latest/
|
|
8
|
+
Project-URL: Changelog, https://github.com/django-commons/django-cookie-consent/blob/master/docs/changelog.rst
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/django-commons/django-cookie-consent/issues
|
|
10
|
+
Project-URL: Source Code, https://github.com/django-commons/django-cookie-consent
|
|
11
|
+
Keywords: cookies,cookie-consent,cookie bar
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Django :: 4.2
|
|
15
|
+
Classifier: Framework :: Django :: 5.1
|
|
16
|
+
Classifier: Framework :: Django :: 5.2
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Operating System :: MacOS
|
|
20
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: django>=4.2
|
|
31
|
+
Requires-Dist: django-appconf
|
|
32
|
+
Provides-Extra: tests
|
|
33
|
+
Requires-Dist: pytest; extra == "tests"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "tests"
|
|
35
|
+
Requires-Dist: pytest-django; extra == "tests"
|
|
36
|
+
Requires-Dist: pytest-playwright; extra == "tests"
|
|
37
|
+
Requires-Dist: hypothesis; extra == "tests"
|
|
38
|
+
Requires-Dist: tox; extra == "tests"
|
|
39
|
+
Requires-Dist: ruff; extra == "tests"
|
|
40
|
+
Provides-Extra: docs
|
|
41
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
42
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
43
|
+
Provides-Extra: release
|
|
44
|
+
Requires-Dist: tbump; extra == "release"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
Django cookie consent
|
|
48
|
+
=====================
|
|
49
|
+
|
|
50
|
+
Manage cookie information and let visitors give or reject consent for them.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
[![Build status][badge:GithubActions:CI]][GithubActions:CI]
|
|
54
|
+
[![Code Quality][badge:GithubActions:CQ]][GithubActions:CQ]
|
|
55
|
+
[![Code style: ruff][badge:ruff]][ruff]
|
|
56
|
+
[![Test coverage][badge:codecov]][codecov]
|
|
57
|
+
[![Documentation][badge:docs]][docs]
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+

|
|
61
|
+
[![PyPI version][badge:pypi]][pypi]
|
|
62
|
+
[![NPM version][badge:npm]][npm]
|
|
63
|
+
|
|
64
|
+
**Features**
|
|
65
|
+
|
|
66
|
+
* cookies and cookie groups are stored in models for easy management
|
|
67
|
+
through Django admin interface
|
|
68
|
+
* support for both opt-in and opt-out cookie consent schemes
|
|
69
|
+
* removing declined cookies (or non accepted when opt-in scheme is used)
|
|
70
|
+
* logging user actions when they accept and decline various cookies
|
|
71
|
+
* easy adding new cookies and seamlessly re-asking for consent for new cookies
|
|
72
|
+
|
|
73
|
+
Documentation
|
|
74
|
+
-------------
|
|
75
|
+
|
|
76
|
+
The documentation is hosted on [readthedocs][docs] and contains all instructions
|
|
77
|
+
to get started.
|
|
78
|
+
|
|
79
|
+
Alternatively, if the documentation is not available, you can consult or build the docs
|
|
80
|
+
from the `docs` directory in this repository.
|
|
81
|
+
|
|
82
|
+
[GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Run+CI%22
|
|
83
|
+
[badge:GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/workflows/Run%20CI/badge.svg
|
|
84
|
+
[GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Code+quality+checks%22
|
|
85
|
+
[badge:GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/workflows/Code%20quality%20checks/badge.svg
|
|
86
|
+
[ruff]: https://github.com/astral-sh/ruff
|
|
87
|
+
[badge:ruff]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
88
|
+
[codecov]: https://codecov.io/gh/django-commons/django-cookie-consent
|
|
89
|
+
[badge:codecov]: https://codecov.io/gh/django-commons/django-cookie-consent/branch/master/graph/badge.svg
|
|
90
|
+
[docs]: https://django-cookie-consent.readthedocs.io/en/latest/?badge=latest
|
|
91
|
+
[badge:docs]: https://readthedocs.org/projects/django-cookie-consent/badge/?version=latest
|
|
92
|
+
[pypi]: https://pypi.org/project/django-cookie-consent/
|
|
93
|
+
[badge:pypi]: https://img.shields.io/pypi/v/django-cookie-consent.svg
|
|
94
|
+
[npm]: https://www.npmjs.com/package/django-cookie-consent
|
|
95
|
+
[badge:npm]: https://img.shields.io/npm/v/django-cookie-consent
|
|
@@ -3,18 +3,17 @@ Django cookie consent
|
|
|
3
3
|
|
|
4
4
|
Manage cookie information and let visitors give or reject consent for them.
|
|
5
5
|
|
|
6
|
-
[![Jazzband][badge:jazzband]][jazzband]
|
|
7
|
-
|
|
8
6
|

|
|
9
7
|
[![Build status][badge:GithubActions:CI]][GithubActions:CI]
|
|
10
8
|
[![Code Quality][badge:GithubActions:CQ]][GithubActions:CQ]
|
|
11
|
-
[![Code style:
|
|
9
|
+
[![Code style: ruff][badge:ruff]][ruff]
|
|
12
10
|
[![Test coverage][badge:codecov]][codecov]
|
|
13
11
|
[![Documentation][badge:docs]][docs]
|
|
14
12
|
|
|
15
13
|

|
|
16
14
|

|
|
17
15
|
[![PyPI version][badge:pypi]][pypi]
|
|
16
|
+
[![NPM version][badge:npm]][npm]
|
|
18
17
|
|
|
19
18
|
**Features**
|
|
20
19
|
|
|
@@ -34,17 +33,17 @@ to get started.
|
|
|
34
33
|
Alternatively, if the documentation is not available, you can consult or build the docs
|
|
35
34
|
from the `docs` directory in this repository.
|
|
36
35
|
|
|
37
|
-
[
|
|
38
|
-
[badge:
|
|
39
|
-
[GithubActions:
|
|
40
|
-
[badge:GithubActions:
|
|
41
|
-
[
|
|
42
|
-
[badge:
|
|
43
|
-
[
|
|
44
|
-
[badge:
|
|
45
|
-
[codecov]: https://codecov.io/gh/jazzband/django-cookie-consent
|
|
46
|
-
[badge:codecov]: https://codecov.io/gh/jazzband/django-cookie-consent/branch/master/graph/badge.svg
|
|
36
|
+
[GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Run+CI%22
|
|
37
|
+
[badge:GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/workflows/Run%20CI/badge.svg
|
|
38
|
+
[GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Code+quality+checks%22
|
|
39
|
+
[badge:GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/workflows/Code%20quality%20checks/badge.svg
|
|
40
|
+
[ruff]: https://github.com/astral-sh/ruff
|
|
41
|
+
[badge:ruff]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
42
|
+
[codecov]: https://codecov.io/gh/django-commons/django-cookie-consent
|
|
43
|
+
[badge:codecov]: https://codecov.io/gh/django-commons/django-cookie-consent/branch/master/graph/badge.svg
|
|
47
44
|
[docs]: https://django-cookie-consent.readthedocs.io/en/latest/?badge=latest
|
|
48
45
|
[badge:docs]: https://readthedocs.org/projects/django-cookie-consent/badge/?version=latest
|
|
49
46
|
[pypi]: https://pypi.org/project/django-cookie-consent/
|
|
50
47
|
[badge:pypi]: https://img.shields.io/pypi/v/django-cookie-consent.svg
|
|
48
|
+
[npm]: https://www.npmjs.com/package/django-cookie-consent
|
|
49
|
+
[badge:npm]: https://img.shields.io/npm/v/django-cookie-consent
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.0"
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
from django.contrib import admin
|
|
2
|
+
from django.db.models import Count
|
|
3
|
+
from django.templatetags.l10n import localize
|
|
4
|
+
from django.templatetags.static import static
|
|
5
|
+
from django.utils.html import format_html
|
|
6
|
+
from django.utils.translation import gettext_lazy as _
|
|
3
7
|
|
|
4
8
|
from .conf import settings
|
|
5
9
|
from .models import Cookie, CookieGroup, LogItem
|
|
@@ -13,7 +17,14 @@ class CookieAdmin(admin.ModelAdmin):
|
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
class CookieGroupAdmin(admin.ModelAdmin):
|
|
16
|
-
list_display = (
|
|
20
|
+
list_display = (
|
|
21
|
+
"varname",
|
|
22
|
+
"name",
|
|
23
|
+
"is_required",
|
|
24
|
+
"is_deletable",
|
|
25
|
+
"num_cookies",
|
|
26
|
+
"get_version",
|
|
27
|
+
)
|
|
17
28
|
search_fields = (
|
|
18
29
|
"varname",
|
|
19
30
|
"name",
|
|
@@ -23,6 +34,22 @@ class CookieGroupAdmin(admin.ModelAdmin):
|
|
|
23
34
|
"is_deletable",
|
|
24
35
|
)
|
|
25
36
|
|
|
37
|
+
def get_queryset(self, request):
|
|
38
|
+
qs = super().get_queryset(request)
|
|
39
|
+
return qs.annotate(num_cookies=Count("cookie"))
|
|
40
|
+
|
|
41
|
+
@admin.display(ordering="num_cookies", description=_("# cookies"))
|
|
42
|
+
def num_cookies(self, obj):
|
|
43
|
+
if (count := obj.num_cookies) > 0:
|
|
44
|
+
return localize(count)
|
|
45
|
+
|
|
46
|
+
return format_html(
|
|
47
|
+
'{count} <img src="{src}" alt="{alt}">',
|
|
48
|
+
count=localize(count),
|
|
49
|
+
src=static("admin/img/icon-alert.svg"),
|
|
50
|
+
alt=_("Warning icon for missing cookies in cookie group."),
|
|
51
|
+
)
|
|
52
|
+
|
|
26
53
|
|
|
27
54
|
class LogItemAdmin(admin.ModelAdmin):
|
|
28
55
|
list_display = ("action", "cookiegroup", "version", "created")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
from django.conf import settings # NOQA
|
|
3
2
|
|
|
4
3
|
from appconf import AppConf
|
|
4
|
+
from django.urls import reverse_lazy
|
|
5
5
|
|
|
6
6
|
__all__ = ["settings"]
|
|
7
7
|
|
|
@@ -25,3 +25,5 @@ class CookieConsentConf(AppConf):
|
|
|
25
25
|
CACHE_BACKEND = "default"
|
|
26
26
|
|
|
27
27
|
LOG_ENABLED = True
|
|
28
|
+
|
|
29
|
+
SUCCESS_URL = reverse_lazy("cookie_consent_cookie_group_list")
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
1
|
from .cache import all_cookie_groups
|
|
5
2
|
from .conf import settings
|
|
6
3
|
from .util import get_cookie_dict_from_request, is_cookie_consent_enabled
|
|
7
4
|
|
|
8
5
|
|
|
9
|
-
def _should_delete_cookie(group_version:
|
|
6
|
+
def _should_delete_cookie(group_version: str | None) -> bool:
|
|
10
7
|
# declined after it was accepted (and set) before
|
|
11
8
|
if group_version == settings.COOKIE_CONSENT_DECLINE:
|
|
12
9
|
return True
|
|
@@ -68,7 +68,8 @@ class Migration(migrations.Migration):
|
|
|
68
68
|
validators=[
|
|
69
69
|
django.core.validators.RegexValidator(
|
|
70
70
|
re.compile("^[-_a-zA-Z0-9]+$"),
|
|
71
|
-
"Enter a valid 'varname' consisting of letters,
|
|
71
|
+
"Enter a valid 'varname' consisting of letters, "
|
|
72
|
+
"numbers, underscores or hyphens.",
|
|
72
73
|
"invalid",
|
|
73
74
|
)
|
|
74
75
|
],
|
|
@@ -7,7 +7,6 @@ from django.db import migrations, models
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Migration(migrations.Migration):
|
|
10
|
-
|
|
11
10
|
dependencies = [
|
|
12
11
|
("cookie_consent", "0002_auto__add_logitem"),
|
|
13
12
|
]
|
|
@@ -22,7 +21,8 @@ class Migration(migrations.Migration):
|
|
|
22
21
|
validators=[
|
|
23
22
|
django.core.validators.RegexValidator(
|
|
24
23
|
re.compile("^[-_a-zA-Z0-9]+$"),
|
|
25
|
-
"Enter a valid 'varname' consisting of letters, numbers,
|
|
24
|
+
"Enter a valid 'varname' consisting of letters, numbers, "
|
|
25
|
+
"underscores or hyphens.",
|
|
26
26
|
"invalid",
|
|
27
27
|
)
|
|
28
28
|
],
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
import re
|
|
3
2
|
from typing import TypedDict
|
|
4
3
|
|
|
@@ -144,7 +143,7 @@ class Cookie(models.Model):
|
|
|
144
143
|
ordering = ["-created"]
|
|
145
144
|
|
|
146
145
|
def __str__(self):
|
|
147
|
-
return "
|
|
146
|
+
return f"{self.name} {self.domain}{self.path}"
|
|
148
147
|
|
|
149
148
|
@clear_cache_after
|
|
150
149
|
def save(self, *args, **kwargs):
|
|
@@ -161,7 +160,8 @@ class Cookie(models.Model):
|
|
|
161
160
|
|
|
162
161
|
@property
|
|
163
162
|
def varname(self):
|
|
164
|
-
|
|
163
|
+
group_varname = self.cookiegroup.varname
|
|
164
|
+
return f"{group_varname}={self.name}:{self.domain}"
|
|
165
165
|
|
|
166
166
|
def get_version(self):
|
|
167
167
|
return self.created.isoformat()
|
|
@@ -185,10 +185,10 @@ class LogItem(models.Model):
|
|
|
185
185
|
version = models.CharField(_("Version"), max_length=32)
|
|
186
186
|
created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True)
|
|
187
187
|
|
|
188
|
-
def __str__(self):
|
|
189
|
-
return "%s %s" % (self.cookiegroup.name, self.version)
|
|
190
|
-
|
|
191
188
|
class Meta:
|
|
192
189
|
verbose_name = _("Log item")
|
|
193
190
|
verbose_name_plural = _("Log items")
|
|
194
191
|
ordering = ["-created"]
|
|
192
|
+
|
|
193
|
+
def __str__(self):
|
|
194
|
+
return f"{self.cookiegroup.name} {self.version}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
@@ -97,6 +97,7 @@ def get_accept_cookie_groups_cookie_string(request, cookie_groups): # pragma: n
|
|
|
97
97
|
"Cookie string template tags for JS are deprecated and will be removed "
|
|
98
98
|
"in django-cookie-consent 1.0",
|
|
99
99
|
DeprecationWarning,
|
|
100
|
+
stacklevel=1,
|
|
100
101
|
)
|
|
101
102
|
cookie_dic = get_cookie_dict_from_request(request)
|
|
102
103
|
for cookie_group in cookie_groups:
|
|
@@ -113,6 +114,7 @@ def get_decline_cookie_groups_cookie_string(request, cookie_groups):
|
|
|
113
114
|
"Cookie string template tags for JS are deprecated and will be removed "
|
|
114
115
|
"in django-cookie-consent 1.0",
|
|
115
116
|
DeprecationWarning,
|
|
117
|
+
stacklevel=1,
|
|
116
118
|
)
|
|
117
119
|
cookie_dic = get_cookie_dict_from_request(request)
|
|
118
120
|
for cookie_group in cookie_groups:
|
|
@@ -133,12 +135,14 @@ def js_type_for_cookie_consent(request, varname, cookie=None):
|
|
|
133
135
|
alert("Social cookie accepted");
|
|
134
136
|
</script>
|
|
135
137
|
"""
|
|
136
|
-
# This approach doesn't work with page caches and/or strict
|
|
137
|
-
# (unless you use nonces, which again doesn't work with
|
|
138
|
+
# This approach doesn't work with page caches and/or strict
|
|
139
|
+
# Content-Security-Policies (unless you use nonces, which again doesn't work with
|
|
140
|
+
# aggressive page caching).
|
|
138
141
|
warnings.warn(
|
|
139
142
|
"Template tags for use in/with JS are deprecated and will be removed "
|
|
140
143
|
"in django-cookie-consent 1.0",
|
|
141
144
|
DeprecationWarning,
|
|
145
|
+
stacklevel=1,
|
|
142
146
|
)
|
|
143
147
|
enabled = is_cookie_consent_enabled(request)
|
|
144
148
|
if not enabled:
|
|
@@ -162,6 +166,12 @@ def accepted_cookies(request):
|
|
|
162
166
|
{{ request|accepted_cookies }}
|
|
163
167
|
|
|
164
168
|
"""
|
|
169
|
+
warnings.warn(
|
|
170
|
+
"The 'accepted_cookies' template filter is deprecated and will be removed"
|
|
171
|
+
"in django-cookie-consent 1.0.",
|
|
172
|
+
DeprecationWarning,
|
|
173
|
+
stacklevel=1,
|
|
174
|
+
)
|
|
165
175
|
return [c.varname for c in get_accepted_cookies(request)]
|
|
166
176
|
|
|
167
177
|
|
|
@@ -1,24 +1,62 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
import datetime
|
|
3
|
-
|
|
2
|
+
import logging
|
|
4
3
|
|
|
5
4
|
from .cache import all_cookie_groups, get_cookie, get_cookie_group
|
|
6
5
|
from .conf import settings
|
|
7
6
|
from .models import ACTION_ACCEPTED, ACTION_DECLINED, LogItem
|
|
8
7
|
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
COOKIE_GROUP_SEP = "|"
|
|
11
|
+
KEY_VALUE_SEP = "="
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_cookie_str(cookie: str) -> dict[str, str]:
|
|
12
15
|
if not cookie:
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
return {}
|
|
17
|
+
|
|
18
|
+
bits = cookie.split(COOKIE_GROUP_SEP)
|
|
19
|
+
|
|
20
|
+
def _gen_pairs():
|
|
21
|
+
for possible_pair in bits:
|
|
22
|
+
parts = possible_pair.split(KEY_VALUE_SEP)
|
|
23
|
+
if len(parts) == 2:
|
|
24
|
+
yield parts
|
|
25
|
+
else:
|
|
26
|
+
logger.debug("cookie_value_discarded", extra={"value": possible_pair})
|
|
27
|
+
|
|
28
|
+
return dict(_gen_pairs())
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _contains_invalid_characters(*inputs: str) -> bool:
|
|
32
|
+
# = and | are special separators. They are unexpected characters in both
|
|
33
|
+
# keys and values.
|
|
34
|
+
for separator in (COOKIE_GROUP_SEP, KEY_VALUE_SEP):
|
|
35
|
+
for value in inputs:
|
|
36
|
+
if separator in value:
|
|
37
|
+
logger.debug("skip_separator", extra={"value": value, "sep": separator})
|
|
38
|
+
return True
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def dict_to_cookie_str(dic) -> str:
|
|
43
|
+
"""
|
|
44
|
+
Serialize a dictionary of cookie-group metadata to a string.
|
|
45
|
+
|
|
46
|
+
The result is stored in a cookie itself. Note that the dictionary keys are expected
|
|
47
|
+
to be cookie group ``varname`` fields, which are validated against a slug regex. The
|
|
48
|
+
values are supposed to be ISO-8601 timestamps.
|
|
49
|
+
|
|
50
|
+
Invalid key/value pairs are dropped.
|
|
51
|
+
"""
|
|
18
52
|
|
|
53
|
+
def _gen_pairs():
|
|
54
|
+
for key, value in dic.items():
|
|
55
|
+
if _contains_invalid_characters(key, value):
|
|
56
|
+
continue
|
|
57
|
+
yield f"{key}={value}"
|
|
19
58
|
|
|
20
|
-
|
|
21
|
-
return "|".join(["%s=%s" % (k, v) for k, v in dic.items() if v])
|
|
59
|
+
return "|".join(_gen_pairs())
|
|
22
60
|
|
|
23
61
|
|
|
24
62
|
def get_cookie_dict_from_request(request):
|
|
@@ -131,7 +169,7 @@ def are_all_cookies_accepted(request):
|
|
|
131
169
|
)
|
|
132
170
|
|
|
133
171
|
|
|
134
|
-
def _get_cookie_groups_by_state(request, state:
|
|
172
|
+
def _get_cookie_groups_by_state(request, state: bool | None):
|
|
135
173
|
return [
|
|
136
174
|
cookie_group
|
|
137
175
|
for cookie_group in get_cookie_groups()
|
|
@@ -171,6 +209,7 @@ def is_cookie_consent_enabled(request):
|
|
|
171
209
|
return enabled
|
|
172
210
|
|
|
173
211
|
|
|
212
|
+
# Deprecated
|
|
174
213
|
def get_cookie_string(cookie_dic):
|
|
175
214
|
"""
|
|
176
215
|
Returns cookie in format suitable for use in javascript.
|
|
@@ -178,7 +217,7 @@ def get_cookie_string(cookie_dic):
|
|
|
178
217
|
expires = datetime.datetime.now() + datetime.timedelta(
|
|
179
218
|
seconds=settings.COOKIE_CONSENT_MAX_AGE
|
|
180
219
|
)
|
|
181
|
-
cookie_str = "
|
|
220
|
+
cookie_str = "{}={}; expires={}; path=/".format(
|
|
182
221
|
settings.COOKIE_CONSENT_NAME,
|
|
183
222
|
dict_to_cookie_str(cookie_dic),
|
|
184
223
|
expires.strftime("%a, %d %b %Y %H:%M:%S GMT"),
|
|
@@ -198,5 +237,5 @@ def get_accepted_cookies(request):
|
|
|
198
237
|
continue
|
|
199
238
|
for cookie in cookie_group.cookie_set.all():
|
|
200
239
|
if version >= cookie.get_version():
|
|
201
|
-
accepted_cookies.append(cookie)
|
|
240
|
+
accepted_cookies.append(cookie) # noqa: PERF401
|
|
202
241
|
return accepted_cookies
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
from django.contrib.auth.views import RedirectURLMixin
|
|
3
2
|
from django.core.exceptions import SuspiciousOperation
|
|
4
3
|
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect, JsonResponse
|
|
@@ -7,6 +6,7 @@ from django.urls import reverse
|
|
|
7
6
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
8
7
|
from django.views.generic import ListView, View
|
|
9
8
|
|
|
9
|
+
from .conf import settings
|
|
10
10
|
from .models import CookieGroup
|
|
11
11
|
from .util import (
|
|
12
12
|
accept_cookies,
|
|
@@ -49,7 +49,7 @@ class CookieGroupBaseProcessView(RedirectURLMixin, View):
|
|
|
49
49
|
require_https=self.request.is_secure(),
|
|
50
50
|
):
|
|
51
51
|
raise SuspiciousOperation("Unsafe open redirect suspected.")
|
|
52
|
-
return redirect_to or
|
|
52
|
+
return redirect_to or settings.COOKIE_CONSENT_SUCCESS_URL
|
|
53
53
|
|
|
54
54
|
def process(self, request, response, varname): # pragma: no cover
|
|
55
55
|
raise NotImplementedError()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-cookie-consent
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Django cookie consent application
|
|
5
|
+
Author-email: Informatika Mihelac <bmihelac@mihelac.org>
|
|
6
|
+
License-Expression: BSD-2-Clause-first-lines
|
|
7
|
+
Project-URL: Documentation, https://django-cookie-consent.readthedocs.io/en/latest/
|
|
8
|
+
Project-URL: Changelog, https://github.com/django-commons/django-cookie-consent/blob/master/docs/changelog.rst
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/django-commons/django-cookie-consent/issues
|
|
10
|
+
Project-URL: Source Code, https://github.com/django-commons/django-cookie-consent
|
|
11
|
+
Keywords: cookies,cookie-consent,cookie bar
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Django :: 4.2
|
|
15
|
+
Classifier: Framework :: Django :: 5.1
|
|
16
|
+
Classifier: Framework :: Django :: 5.2
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Operating System :: MacOS
|
|
20
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: django>=4.2
|
|
31
|
+
Requires-Dist: django-appconf
|
|
32
|
+
Provides-Extra: tests
|
|
33
|
+
Requires-Dist: pytest; extra == "tests"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "tests"
|
|
35
|
+
Requires-Dist: pytest-django; extra == "tests"
|
|
36
|
+
Requires-Dist: pytest-playwright; extra == "tests"
|
|
37
|
+
Requires-Dist: hypothesis; extra == "tests"
|
|
38
|
+
Requires-Dist: tox; extra == "tests"
|
|
39
|
+
Requires-Dist: ruff; extra == "tests"
|
|
40
|
+
Provides-Extra: docs
|
|
41
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
42
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
43
|
+
Provides-Extra: release
|
|
44
|
+
Requires-Dist: tbump; extra == "release"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
Django cookie consent
|
|
48
|
+
=====================
|
|
49
|
+
|
|
50
|
+
Manage cookie information and let visitors give or reject consent for them.
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
[![Build status][badge:GithubActions:CI]][GithubActions:CI]
|
|
54
|
+
[![Code Quality][badge:GithubActions:CQ]][GithubActions:CQ]
|
|
55
|
+
[![Code style: ruff][badge:ruff]][ruff]
|
|
56
|
+
[![Test coverage][badge:codecov]][codecov]
|
|
57
|
+
[![Documentation][badge:docs]][docs]
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+

|
|
61
|
+
[![PyPI version][badge:pypi]][pypi]
|
|
62
|
+
[![NPM version][badge:npm]][npm]
|
|
63
|
+
|
|
64
|
+
**Features**
|
|
65
|
+
|
|
66
|
+
* cookies and cookie groups are stored in models for easy management
|
|
67
|
+
through Django admin interface
|
|
68
|
+
* support for both opt-in and opt-out cookie consent schemes
|
|
69
|
+
* removing declined cookies (or non accepted when opt-in scheme is used)
|
|
70
|
+
* logging user actions when they accept and decline various cookies
|
|
71
|
+
* easy adding new cookies and seamlessly re-asking for consent for new cookies
|
|
72
|
+
|
|
73
|
+
Documentation
|
|
74
|
+
-------------
|
|
75
|
+
|
|
76
|
+
The documentation is hosted on [readthedocs][docs] and contains all instructions
|
|
77
|
+
to get started.
|
|
78
|
+
|
|
79
|
+
Alternatively, if the documentation is not available, you can consult or build the docs
|
|
80
|
+
from the `docs` directory in this repository.
|
|
81
|
+
|
|
82
|
+
[GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Run+CI%22
|
|
83
|
+
[badge:GithubActions:CI]: https://github.com/django-commons/django-cookie-consent/workflows/Run%20CI/badge.svg
|
|
84
|
+
[GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/actions?query=workflow%3A%22Code+quality+checks%22
|
|
85
|
+
[badge:GithubActions:CQ]: https://github.com/django-commons/django-cookie-consent/workflows/Code%20quality%20checks/badge.svg
|
|
86
|
+
[ruff]: https://github.com/astral-sh/ruff
|
|
87
|
+
[badge:ruff]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
88
|
+
[codecov]: https://codecov.io/gh/django-commons/django-cookie-consent
|
|
89
|
+
[badge:codecov]: https://codecov.io/gh/django-commons/django-cookie-consent/branch/master/graph/badge.svg
|
|
90
|
+
[docs]: https://django-cookie-consent.readthedocs.io/en/latest/?badge=latest
|
|
91
|
+
[badge:docs]: https://readthedocs.org/projects/django-cookie-consent/badge/?version=latest
|
|
92
|
+
[pypi]: https://pypi.org/project/django-cookie-consent/
|
|
93
|
+
[badge:pypi]: https://img.shields.io/pypi/v/django-cookie-consent.svg
|
|
94
|
+
[npm]: https://www.npmjs.com/package/django-cookie-consent
|
|
95
|
+
[badge:npm]: https://img.shields.io/npm/v/django-cookie-consent
|
|
@@ -3,7 +3,6 @@ LICENSE
|
|
|
3
3
|
MANIFEST.in
|
|
4
4
|
README.md
|
|
5
5
|
pyproject.toml
|
|
6
|
-
setup.cfg
|
|
7
6
|
cookie_consent/__init__.py
|
|
8
7
|
cookie_consent/admin.py
|
|
9
8
|
cookie_consent/apps.py
|
|
@@ -33,6 +32,7 @@ django_cookie_consent.egg-info/SOURCES.txt
|
|
|
33
32
|
django_cookie_consent.egg-info/dependency_links.txt
|
|
34
33
|
django_cookie_consent.egg-info/requires.txt
|
|
35
34
|
django_cookie_consent.egg-info/top_level.txt
|
|
35
|
+
tests/test_admin.py
|
|
36
36
|
tests/test_cache.py
|
|
37
37
|
tests/test_cookie_group_model.py
|
|
38
38
|
tests/test_cookie_model.py
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
django>=4.2
|
|
2
2
|
django-appconf
|
|
3
3
|
|
|
4
|
-
[coverage]
|
|
5
|
-
pytest-cov
|
|
6
|
-
|
|
7
4
|
[docs]
|
|
8
5
|
sphinx
|
|
9
6
|
sphinx-rtd-theme
|
|
@@ -13,9 +10,9 @@ tbump
|
|
|
13
10
|
|
|
14
11
|
[tests]
|
|
15
12
|
pytest
|
|
13
|
+
pytest-cov
|
|
16
14
|
pytest-django
|
|
17
15
|
pytest-playwright
|
|
16
|
+
hypothesis
|
|
18
17
|
tox
|
|
19
|
-
|
|
20
|
-
black
|
|
21
|
-
flake8
|
|
18
|
+
ruff
|