django-cookie-consent 0.5.0b0__py3-none-any.whl → 0.6.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.
@@ -1 +1 @@
1
- __version__ = "0.5.0b0"
1
+ __version__ = "0.6.0"
cookie_consent/cache.py CHANGED
@@ -1,10 +1,11 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from django.core.cache import caches
3
3
 
4
- from cookie_consent.conf import settings
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,20 +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
- items = cache.get(CACHE_KEY)
29
- if items is None:
30
- from cookie_consent.models import CookieGroup
31
-
32
- qs = CookieGroup.objects.filter(is_required=False)
33
- qs = qs.prefetch_related("cookie_set")
34
- # items = qs.in_bulk(field_name="varname")
35
- # FIXME -> doesn't work because varname is not a unique fieldl, we need to
36
- # make this unique
37
- items = {group.varname: group for group in qs}
38
- cache.set(CACHE_KEY, items, CACHE_TIMEOUT)
39
- return items
40
+ return cache.get_or_set(
41
+ CACHE_KEY, _get_cookie_groups_from_db, timeout=CACHE_TIMEOUT
42
+ )
40
43
 
41
44
 
42
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
+ ]
cookie_consent/models.py CHANGED
@@ -6,8 +6,6 @@ from django.core.validators import RegexValidator
6
6
  from django.db import models
7
7
  from django.utils.translation import gettext_lazy as _
8
8
 
9
- from cookie_consent.cache import delete_cache
10
-
11
9
  COOKIE_NAME_RE = re.compile(r"^[-_a-zA-Z0-9]+$")
12
10
  validate_cookie_name = RegexValidator(
13
11
  COOKIE_NAME_RE,
@@ -19,6 +17,17 @@ validate_cookie_name = RegexValidator(
19
17
  )
20
18
 
21
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
+
22
31
  class CookieGroupDict(TypedDict):
23
32
  varname: str
24
33
  name: str
@@ -29,9 +38,27 @@ class CookieGroupDict(TypedDict):
29
38
  # version: str
30
39
 
31
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
+
32
56
  class CookieGroup(models.Model):
33
57
  varname = models.CharField(
34
- _("Variable name"), max_length=32, validators=[validate_cookie_name]
58
+ _("Variable name"),
59
+ max_length=32,
60
+ unique=True,
61
+ validators=[validate_cookie_name],
35
62
  )
36
63
  name = models.CharField(_("Name"), max_length=100, blank=True)
37
64
  description = models.TextField(_("Description"), blank=True)
@@ -48,6 +75,8 @@ class CookieGroup(models.Model):
48
75
  ordering = models.IntegerField(_("Ordering"), default=0)
49
76
  created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True)
50
77
 
78
+ objects = CookieGroupManager()
79
+
51
80
  class Meta:
52
81
  verbose_name = _("Cookie Group")
53
82
  verbose_name_plural = _("Cookie Groups")
@@ -56,20 +85,23 @@ class CookieGroup(models.Model):
56
85
  def __str__(self):
57
86
  return self.name
58
87
 
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
+
59
99
  def get_version(self) -> str:
60
100
  try:
61
101
  return str(self.cookie_set.all()[0].get_version())
62
102
  except IndexError:
63
103
  return ""
64
104
 
65
- def delete(self, *args, **kwargs):
66
- super(CookieGroup, self).delete(*args, **kwargs)
67
- delete_cache()
68
-
69
- def save(self, *args, **kwargs):
70
- super(CookieGroup, self).save(*args, **kwargs)
71
- delete_cache()
72
-
73
105
  def for_json(self) -> CookieGroupDict:
74
106
  return {
75
107
  "varname": self.varname,
@@ -80,6 +112,12 @@ class CookieGroup(models.Model):
80
112
  }
81
113
 
82
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)
119
+
120
+
83
121
  class Cookie(models.Model):
84
122
  cookiegroup = models.ForeignKey(
85
123
  CookieGroup,
@@ -92,14 +130,35 @@ class Cookie(models.Model):
92
130
  domain = models.CharField(_("Domain"), max_length=250, blank=True)
93
131
  created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True)
94
132
 
133
+ objects = CookieManager()
134
+
95
135
  class Meta:
96
136
  verbose_name = _("Cookie")
97
137
  verbose_name_plural = _("Cookies")
138
+ constraints = [
139
+ models.UniqueConstraint(
140
+ fields=("cookiegroup", "name", "domain"),
141
+ name="natural_key",
142
+ ),
143
+ ]
98
144
  ordering = ["-created"]
99
145
 
100
146
  def __str__(self):
101
147
  return "%s %s%s" % (self.name, self.domain, self.path)
102
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
+
103
162
  @property
104
163
  def varname(self):
105
164
  return "%s=%s:%s" % (self.cookiegroup.varname, self.name, self.domain)
@@ -107,14 +166,6 @@ class Cookie(models.Model):
107
166
  def get_version(self):
108
167
  return self.created.isoformat()
109
168
 
110
- def delete(self, *args, **kwargs):
111
- super(Cookie, self).delete(*args, **kwargs)
112
- delete_cache()
113
-
114
- def save(self, *args, **kwargs):
115
- super(Cookie, self).save(*args, **kwargs)
116
- delete_cache()
117
-
118
169
 
119
170
  ACTION_ACCEPTED = 1
120
171
  ACTION_DECLINED = -1
@@ -1,203 +1,163 @@
1
- /**
2
- * Cookiebar functionality, as a Javascript module.
3
- *
4
- * About modules: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
5
- *
6
- * The code is organized here in a way to make the templates work with Django's page
7
- * cache. This means that anything user-specific (so different django session and even
8
- * cookie consent cookies) cannot be baked into the templates, as that breaks caches.
9
- *
10
- * The cookie bar operates on the following principles:
11
- *
12
- * - The developer using the library includes the desired template in their django
13
- * templates, using the HTML <template> element. This contains the content for the
14
- * cookie bar.
15
- * - The developer is responsible for loading some Javascript that loads this script.
16
- * - The main export of this script needs to be called (showCookieBar), with the
17
- * appropriate options.
18
- * - The options include the backend URLs where the retrieve data, which selectors/DOM
19
- * nodes to use for various functionality and the hooks to tap into the accept/decline
20
- * life-cycle.
21
- * - When a user accepts or declines (all) cookies, the call to the backend is made via
22
- * a fetch request, bypassing any page caches and preventing full-page reloads.
23
- */
24
- const DEFAULTS = {
25
- statusUrl: undefined,
26
- // TODO: also accept element rather than selector?
27
- templateSelector: '#cookie-consent__cookie-bar',
28
- cookieGroupsSelector: '#cookie-consent__cookie-groups',
29
- acceptSelector: '.cookie-consent__accept',
30
- declineSelector: '.cookie-consent__decline',
31
- /**
32
- * Either a string (selector), DOMNode or null.
33
- *
34
- * If null, the bar is appended to the body. If provided, the node is used or looked
35
- * up.
36
- */
37
- insertBefore: null,
38
- onShow: null, // callback when the cookie bar is being shown -> add class to body...
39
- onAccept: null, // callback when cookies are accepted
40
- onDecline: null, // callback when cookies are declined
41
- csrfHeaderName: 'X-CSRFToken', // Django's default, can be overridden with settings.CSRF_HEADER_NAME
1
+ // src/cookiebar.ts
2
+ var DEFAULT_FETCH_HEADERS = {
3
+ "X-Cookie-Consent-Fetch": "1"
42
4
  };
43
-
44
- const DEFAULT_HEADERS = {'X-Cookie-Consent-Fetch': '1'};
45
-
46
- let CONFIGURATION = DEFAULTS;
47
- /**
48
- * Cookie accept status, including the accept/decline URLs, csrftoken... See
49
- * backend view CookieStatusView.
50
- */
51
- let COOKIE_STATUS = null;
52
-
53
- export const loadCookieGroups = (selector) => {
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) => {
54
45
  const node = document.querySelector(selector);
55
46
  if (!node) {
56
47
  throw new Error(`No cookie groups (script) tag found, using selector: '${selector}'`);
57
48
  }
58
49
  return JSON.parse(node.innerText);
59
50
  };
60
-
61
- const doInsertBefore = (beforeNode, newNode) => {
51
+ var doInsertBefore = (beforeNode, newNode) => {
62
52
  const parent = beforeNode.parentNode;
53
+ if (parent === null)
54
+ throw new Error("Reference node doesn't have a parent.");
63
55
  parent.insertBefore(newNode, beforeNode);
64
- }
65
-
66
- /**
67
- * Register the accept/decline event handlers.
68
- *
69
- * Note that we can't just set the decline or accept cookie purely client-side, as the
70
- * cookie possibly has the httpOnly flag set.
71
- *
72
- * @param {HTMLEelement} cookieBarNode The DOM node containing the cookiebar markup.
73
- * @param {Array} cookieGroups The array of all configured cookie groups.
74
- * @return {Void}
75
- */
76
- const registerEvents = (cookieBarNode, cookieGroups) => {
77
- const {acceptSelector, onAccept, declineSelector, onDecline} = CONFIGURATION;
78
- const {
79
- acceptedCookieGroups: accepted,
80
- declinedCookieGroups: declined,
81
- notAcceptedOrDeclinedCookieGroups: undecided,
82
- } = COOKIE_STATUS;
83
-
84
- cookieBarNode
85
- .querySelector(acceptSelector)
86
- .addEventListener('click', event => {
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) => {
87
72
  event.preventDefault();
88
73
  const acceptedGroups = filterCookieGroups(cookieGroups, accepted.concat(undecided));
89
- onAccept?.(acceptedGroups, event);
90
- acceptCookiesBackend();
74
+ onAccept == null ? void 0 : onAccept(acceptedGroups, event);
75
+ client.saveCookiesStatusBackend("acceptUrl");
91
76
  cookieBarNode.parentNode.removeChild(cookieBarNode);
92
77
  });
93
-
94
- cookieBarNode
95
- .querySelector(declineSelector)
96
- .addEventListener('click', event => {
78
+ }
79
+ const declineNode = cookieBarNode.querySelector(declineSelector);
80
+ if (declineNode) {
81
+ declineNode.addEventListener("click", (event) => {
97
82
  event.preventDefault();
98
83
  const declinedGroups = filterCookieGroups(cookieGroups, declined.concat(undecided));
99
- onDecline?.(declinedGroups, event);
100
- declineCookiesBackend();
84
+ onDecline == null ? void 0 : onDecline(declinedGroups, event);
85
+ client.saveCookiesStatusBackend("declineUrl");
101
86
  cookieBarNode.parentNode.removeChild(cookieBarNode);
102
87
  });
88
+ }
103
89
  };
104
-
105
- const loadCookieStatus = async () => {
106
- const {statusUrl} = CONFIGURATION;
107
- if (!statusUrl) console.error('Missing status URL option, did you forget to pass the statusUrl option?');
108
- const response = await window.fetch(
109
- CONFIGURATION.statusUrl,
110
- {
111
- method: 'GET',
112
- credentials: 'same-origin',
113
- headers: DEFAULT_HEADERS
114
- }
115
- );
116
- // assign to module level variable, once the page is loaded these details should
117
- // not change.
118
- COOKIE_STATUS = await response.json();
90
+ var filterCookieGroups = (cookieGroups, varNames) => {
91
+ return cookieGroups.filter((group) => varNames.includes(group.varname));
119
92
  };
120
-
121
- const saveCookiesStatusBackend = async (urlProperty) => {
122
- const status = COOKIE_STATUS || {};
123
- const url = status[urlProperty];
124
- if (!url) {
125
- console.error(`Missing url for ${urlProperty} - was the cookie status not loaded properly?`);
126
- return;
127
- }
128
- await window.fetch(url, {
129
- method: 'POST',
130
- credentials: 'same-origin',
131
- headers: {
132
- ...DEFAULT_HEADERS,
133
- [CONFIGURATION.csrfHeaderName]: status.csrftoken
134
- }
135
- });
93
+ function cloneNode(node) {
94
+ return node.cloneNode(true);
136
95
  }
137
-
138
- /**
139
- * Make the call to the backend to accept the cookies.
140
- */
141
- const acceptCookiesBackend = async () => await saveCookiesStatusBackend('acceptUrl');
142
- /**
143
- * Make the call to the backend to decline the cookies.
144
- */
145
- const declineCookiesBackend = async () => await saveCookiesStatusBackend('declineUrl');
146
-
147
- /**
148
- * Filter the cookie groups down to a subset of specified varnames.
149
- */
150
- const filterCookieGroups = (cookieGroups, varNames) => {
151
- return cookieGroups.filter(group => varNames.includes(group.varname));
152
- };
153
-
154
- export const showCookieBar = async (options={}) => {
155
- // merge defaults and provided options
156
- CONFIGURATION = {...DEFAULTS, ...options};
96
+ var showCookieBar = async (options = {}) => {
157
97
  const {
158
- cookieGroupsSelector,
159
- templateSelector,
160
- insertBefore,
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,
161
103
  onShow,
162
104
  onAccept,
163
105
  onDecline,
164
- } = CONFIGURATION;
106
+ statusUrl = "",
107
+ csrfHeaderName = "X-CSRFToken"
108
+ // Django's default, can be overridden with settings.CSRF_HEADER_NAME
109
+ } = options;
165
110
  const cookieGroups = loadCookieGroups(cookieGroupsSelector);
166
-
167
- // no cookie groups -> abort
168
- if (!cookieGroups.length) return;
169
-
111
+ if (!cookieGroups.length)
112
+ return;
170
113
  const templateNode = document.querySelector(templateSelector);
171
-
172
- // insert before a given node, if specified, or append to the body as default behaviour
173
- const doInsert = insertBefore === null
174
- ? (cookieBarNode) => document.querySelector('body').appendChild(cookieBarNode)
175
- : typeof insertBefore === 'string'
176
- ? (cookieBarNode) => doInsertBefore(document.querySelector(insertBefore), cookieBarNode)
177
- : (cookieBarNode) => doInsertBefore(insertBefore, cookieBarNode)
178
- ;
179
- await loadCookieStatus();
180
-
181
- // calculate the cookie groups to invoke the callbacks. We deliberately fire those
182
- // without awaiting so that our cookie bar is shown/hidden as soon as possible.
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();
183
127
  const {
184
- acceptedCookieGroups: accepted,
185
- declinedCookieGroups: declined,
128
+ acceptedCookieGroups,
129
+ declinedCookieGroups,
186
130
  notAcceptedOrDeclinedCookieGroups
187
- } = COOKIE_STATUS;
188
-
189
- const acceptedGroups = filterCookieGroups(cookieGroups, accepted);
190
- if (acceptedGroups.length) onAccept?.(acceptedGroups);
191
- const declinedGroups = filterCookieGroups(cookieGroups, declined);
192
- if (declinedGroups.length) onDecline?.(declinedGroups);
193
-
194
- // there are no (more) cookie groups to accept, don't show the bar
195
- if (!notAcceptedOrDeclinedCookieGroups.length) return;
196
-
197
- // grab the contents from the template node and add them to the DOM, optionally
198
- // calling the onShow callback
199
- const cookieBarNode = templateNode.content.firstElementChild.cloneNode(true);
200
- registerEvents(cookieBarNode, cookieGroups);
201
- onShow?.();
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
+ });
202
156
  doInsert(cookieBarNode);
157
+ onShow == null ? void 0 : onShow();
158
+ };
159
+ export {
160
+ loadCookieGroups,
161
+ showCookieBar
203
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
+ }
cookie_consent/views.py CHANGED
@@ -1,11 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
+ from django.contrib.auth.views import RedirectURLMixin
2
3
  from django.core.exceptions import SuspiciousOperation
3
4
  from django.http import HttpRequest, HttpResponse, HttpResponseRedirect, JsonResponse
4
5
  from django.middleware.csrf import get_token as get_csrf_token
5
6
  from django.urls import reverse
7
+ from django.utils.http import url_has_allowed_host_and_scheme
6
8
  from django.views.generic import ListView, View
7
9
 
8
- from .compat import RedirectURLMixin, url_has_allowed_host_and_scheme
9
10
  from .models import CookieGroup
10
11
  from .util import (
11
12
  accept_cookies,
@@ -11,3 +11,4 @@ The following is a list of much appreciated contributors:
11
11
  * Abdullah Alahdal (alahdal)
12
12
  * some1ataplace
13
13
  * binoyudayan
14
+ * adilhussain540
@@ -1,11 +1,32 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-cookie-consent
3
- Version: 0.5.0b0
3
+ Version: 0.6.0
4
4
  Summary: Django cookie consent application
5
- Home-page: https://github.com/jazzband/django-cookie-consent
6
- Author: Informatika Mihelac
7
- Author-email: bmihelac@mihelac.org
8
- License: BSD
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
@@ -13,9 +34,8 @@ Project-URL: Source Code, https://github.com/jazzband/django-cookie-consent
13
34
  Keywords: cookies,cookie-consent,cookie bar
14
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,22 +46,21 @@ 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
31
53
  License-File: LICENSE
32
54
  License-File: AUTHORS
33
- Requires-Dist: django >=3.2
55
+ Requires-Dist: django >=4.2
34
56
  Requires-Dist: django-appconf
35
57
  Provides-Extra: coverage
36
58
  Requires-Dist: pytest-cov ; extra == 'coverage'
37
59
  Provides-Extra: docs
38
60
  Requires-Dist: sphinx ; extra == 'docs'
39
61
  Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
40
- Provides-Extra: pep8
41
- Requires-Dist: flake8 ; extra == 'pep8'
42
62
  Provides-Extra: release
43
63
  Requires-Dist: tbump ; extra == 'release'
44
- Requires-Dist: twine ; extra == 'release'
45
64
  Provides-Extra: tests
46
65
  Requires-Dist: pytest ; extra == 'tests'
47
66
  Requires-Dist: pytest-django ; extra == 'tests'
@@ -1,28 +1,30 @@
1
- cookie_consent/__init__.py,sha256=dOConuWcry21fudkiQhlg2ykFSpmcOjEK2ytveI7SmA,24
1
+ cookie_consent/__init__.py,sha256=cID1jLnC_vj48GgMN6Yb1FA3JsQ95zNmCHmRYE8TFhY,22
2
2
  cookie_consent/admin.py,sha256=9IoTczdhLqbn4QMuJSbIWNe6dahj6niiOz3IDKw4sk4,1112
3
3
  cookie_consent/apps.py,sha256=nldd3hZnNChnrajmCD3crvxFfieWgLi625grNTEVYis,248
4
- cookie_consent/cache.py,sha256=B-65iwYvyR6kbT5LIiGb2PDLUwnW2xr3xHWTbDf9qsc,1446
5
- cookie_consent/compat.py,sha256=6zIzPpufUOlSr6J1bvJdacYhenIVrKMfOOS995mflUQ,464
4
+ cookie_consent/cache.py,sha256=ZiWDxyYjGoOCV4JjCKPoBCkrM69Xbybjfzq_az4XcZc,1408
6
5
  cookie_consent/conf.py,sha256=Q-xpL-HgxMf1PTrZL7TtGOdOUgaUYs8_d1ZwBipK7Nk,555
7
6
  cookie_consent/middleware.py,sha256=DvpJC-YabhAt-8V2u6mTdpzGN1q833nnuAeO4E9cBaA,1981
8
- cookie_consent/models.py,sha256=hPDyyerJeVExLVB_yLJl4jKiqRdghDSO_QYwtZ_lbBs,4242
7
+ cookie_consent/models.py,sha256=Zpt1w_xa8pmkhIAdc2yJ4GiV0-VllLHFpQsWnNEWylE,5520
9
8
  cookie_consent/urls.py,sha256=U5ssRnjWoJM3GynERe0CUVsDdZ0-98BKX6vyimg312A,1119
10
9
  cookie_consent/util.py,sha256=vS0bd9WJDnEpS8lBlBTJCbApJw8Flr98Rh-D0edjIQs,5948
11
- cookie_consent/views.py,sha256=OPeWNXCp3zEZAR7EE4UnCtaHqQAWYORHI3RMrEi54x4,4126
10
+ cookie_consent/views.py,sha256=bkSMs8i9A-kSdgULNijGKDzphaRXzmZd0kcbX57aQjM,4173
12
11
  cookie_consent/fixtures/common_cookies.json,sha256=iOEeMtZhERoeoxBz5Kj-Mo_XOUk5F1ljNon4w2odBJo,2449
13
12
  cookie_consent/migrations/0001_initial.py,sha256=jIGX_k1nIm7GGpqgE-zvI1NIBizD8wkxYEb-BL6FR4c,4180
14
13
  cookie_consent/migrations/0002_auto__add_logitem.py,sha256=rZ_kkXI3eij3k6PiGP5CsA41psENNZBbMD0qwUxBBTM,1633
14
+ cookie_consent/migrations/0003_alter_cookiegroup_varname.py,sha256=Cebn_m9mMo231NKegc9GU1LBLGLX5u3doO6Qvw-8PeA,873
15
+ cookie_consent/migrations/0004_cookie_natural_key.py,sha256=KAQy71oe2sJjz0xwB5dPDL9LBjFd4gqdZfNwiAVhs0Y,466
15
16
  cookie_consent/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
17
  cookie_consent/static/cookie_consent/cookiebar.js,sha256=vdouyXSBRkzKDiLdMAdOTWKzNO3vgXZNehUTIVUW5Gk,1919
17
- cookie_consent/static/cookie_consent/cookiebar.module.js,sha256=9h1i6AhvNhxw6kl9vC4T72uXTHmWpgy5Le0ezyChDh4,7371
18
+ cookie_consent/static/cookie_consent/cookiebar.module.js,sha256=0RSPojS9J47HzEkY0xpAK5yJjWPU2ZcxFNMc8kHUCp0,5625
19
+ cookie_consent/static/cookie_consent/cookiebar.module.js.map,sha256=D7H9fwNVaaKgdM0pdaFW2mva0sgwHOO7h8vovh2SCVs,14288
18
20
  cookie_consent/templates/cookie_consent/_cookie_group.html,sha256=wozvbdRjuKu3gnegN8vex_lDkku22pne830NWuzHXVw,1496
19
21
  cookie_consent/templates/cookie_consent/base.html,sha256=ghOQ9vqSzKG32LfSQmj5xTF1PBs-SDtQEcOC1wjAemQ,85
20
22
  cookie_consent/templates/cookie_consent/cookiegroup_list.html,sha256=PMO9iLxQrgRpQGLC0stlDamMonc3tLS3o5PWPF378Zg,308
21
23
  cookie_consent/templatetags/__init__.py,sha256=FZk9hm7vBsK8G16pNugputbrrEciYqJc_XRAhTCcojI,46
22
24
  cookie_consent/templatetags/cookie_consent_tags.py,sha256=gBn1Z61KeFcCRd368zxYCN9FJFQ1x5RX2E12ricdRgU,5175
23
- django_cookie_consent-0.5.0b0.dist-info/AUTHORS,sha256=1IpYKADNdC03tx3VzMmPLRJo8MHHC_JlWcPEcdcTDA8,323
24
- django_cookie_consent-0.5.0b0.dist-info/LICENSE,sha256=ZZi-io1uazO5jpDoNJScUfjeVI2dEzvDPOcyFhU0KYw,1349
25
- django_cookie_consent-0.5.0b0.dist-info/METADATA,sha256=xxKagY9VvX-6lpC3rAasVdWAWqUnarscSoelQ1cX8aQ,4660
26
- django_cookie_consent-0.5.0b0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
27
- django_cookie_consent-0.5.0b0.dist-info/top_level.txt,sha256=wD8Ix58rJguYeYfils_Z40QfVybiRYb1vwRNm09HN4M,15
28
- django_cookie_consent-0.5.0b0.dist-info/RECORD,,
25
+ django_cookie_consent-0.6.0.dist-info/AUTHORS,sha256=9Eey8K2GsZr5vWe3ZD3_oqA9aFgciNIVMTmyO5eq5rw,340
26
+ django_cookie_consent-0.6.0.dist-info/LICENSE,sha256=ZZi-io1uazO5jpDoNJScUfjeVI2dEzvDPOcyFhU0KYw,1349
27
+ django_cookie_consent-0.6.0.dist-info/METADATA,sha256=DCxTzS3v_qAwYuzfC7AkhXZ_cpYdgJFNfzR-dzMNU54,6053
28
+ django_cookie_consent-0.6.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
29
+ django_cookie_consent-0.6.0.dist-info/top_level.txt,sha256=wD8Ix58rJguYeYfils_Z40QfVybiRYb1vwRNm09HN4M,15
30
+ django_cookie_consent-0.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
cookie_consent/compat.py DELETED
@@ -1,13 +0,0 @@
1
- try:
2
- from django.utils.http import url_has_allowed_host_and_scheme
3
- except ImportError: # django < 3.0
4
- from django.utils.http import is_safe_url as url_has_allowed_host_and_scheme
5
-
6
- try: # django >= 4.1
7
- from django.contrib.auth.views import RedirectURLMixin
8
- except ImportError:
9
- from django.contrib.auth.views import (
10
- SuccessURLAllowedHostsMixin as RedirectURLMixin,
11
- )
12
-
13
- __all__ = ["url_has_allowed_host_and_scheme", "RedirectURLMixin"]