diff --git a/cookie_consent/migrations/0004_cookie_natural_key.py b/cookie_consent/migrations/0004_cookie_natural_key.py new file mode 100644 index 0000000..6dfa54a --- /dev/null +++ b/cookie_consent/migrations/0004_cookie_natural_key.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.13 on 2024-05-09 20:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("cookie_consent", "0003_alter_cookiegroup_varname"), + ] + + operations = [ + migrations.AddConstraint( + model_name="cookie", + constraint=models.UniqueConstraint( + fields=("cookiegroup", "name", "domain"), name="natural_key" + ), + ), + ] diff --git a/cookie_consent/models.py b/cookie_consent/models.py index 7fe0d85..c9a66ba 100644 --- a/cookie_consent/models.py +++ b/cookie_consent/models.py @@ -48,6 +48,11 @@ def update(self, **kwargs): return super().update(**kwargs) +class CookieGroupManager(models.Manager.from_queryset(BaseQueryset)): + def get_by_natural_key(self, varname): + return self.get(varname=varname) + + class CookieGroup(models.Model): varname = models.CharField( _("Variable name"), @@ -70,7 +75,7 @@ class CookieGroup(models.Model): ordering = models.IntegerField(_("Ordering"), default=0) created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True) - objects = BaseQueryset.as_manager() + objects = CookieGroupManager() class Meta: verbose_name = _("Cookie Group") @@ -88,6 +93,9 @@ def save(self, *args, **kwargs): def delete(self, *args, **kwargs): return super().delete(*args, **kwargs) + def natural_key(self): + return (self.varname,) + def get_version(self) -> str: try: return str(self.cookie_set.all()[0].get_version()) @@ -104,6 +112,12 @@ def for_json(self) -> CookieGroupDict: } +class CookieManager(models.Manager.from_queryset(BaseQueryset)): + def get_by_natural_key(self, name, domain, cookiegroup): + group = CookieGroup.objects.get_by_natural_key(cookiegroup) + return self.get(cookiegroup=group, name=name, domain=domain) + + class Cookie(models.Model): cookiegroup = models.ForeignKey( CookieGroup, @@ -116,11 +130,17 @@ class Cookie(models.Model): domain = models.CharField(_("Domain"), max_length=250, blank=True) created = models.DateTimeField(_("Created"), auto_now_add=True, blank=True) - objects = BaseQueryset.as_manager() + objects = CookieManager() class Meta: verbose_name = _("Cookie") verbose_name_plural = _("Cookies") + constraints = [ + models.UniqueConstraint( + fields=("cookiegroup", "name", "domain"), + name="natural_key", + ), + ] ordering = ["-created"] def __str__(self): @@ -134,6 +154,11 @@ def save(self, *args, **kwargs): def delete(self, *args, **kwargs): return super().delete(*args, **kwargs) + def natural_key(self): + return (self.name, self.domain) + self.cookiegroup.natural_key() + + natural_key.dependencies = ["cookie_consent.cookiegroup"] + @property def varname(self): return "%s=%s:%s" % (self.cookiegroup.varname, self.name, self.domain) diff --git a/docs/changelog.rst b/docs/changelog.rst index ad28241..a5dd5f9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,8 +6,9 @@ Changelog ------------------ 💥 This feature release has a potential breaking change. The ``CookieGroup.varname`` -field now has a unique constraint on it. If you have duplicate values, this migration -will crash. +field now has a unique constraint on it. The ``Cookie`` model now has a unique +constraint on ``cookiegroup``, ``name`` and ``domain``. If you have duplicate values, +this migration will crash. * ... diff --git a/tests/test_cookie_group_model.py b/tests/test_cookie_group_model.py new file mode 100644 index 0000000..0a979bc --- /dev/null +++ b/tests/test_cookie_group_model.py @@ -0,0 +1,19 @@ +import pytest + +from cookie_consent.models import CookieGroup + + +def test_natural_key(): + group = CookieGroup(varname="social") + + assert group.natural_key() == ("social",) + + +@pytest.mark.django_db +def test_load_by_natural_key(): + social_group = CookieGroup.objects.create(varname="social") + CookieGroup.objects.create(varname="other") + + loaded_group = CookieGroup.objects.get_by_natural_key("social") + + assert loaded_group == social_group diff --git a/tests/test_cookie_model.py b/tests/test_cookie_model.py new file mode 100644 index 0000000..58111a5 --- /dev/null +++ b/tests/test_cookie_model.py @@ -0,0 +1,24 @@ +import pytest + +from cookie_consent.models import Cookie, CookieGroup + + +def test_natural_key(): + cookie = Cookie( + cookiegroup=CookieGroup(varname="analytics"), name="trck", domain="example.com" + ) + + assert cookie.natural_key() == ("trck", "example.com", "analytics") + + +@pytest.mark.django_db +def test_load_by_natural_key(): + social_group = CookieGroup.objects.create(varname="social") + cookie = Cookie.objects.create( + cookiegroup=social_group, name="trck", domain="example.com" + ) + Cookie.objects.create(cookiegroup=social_group, name="other", domain="example.com") + + loaded_cookie = Cookie.objects.get_by_natural_key("trck", "example.com", "social") + + assert loaded_cookie == cookie diff --git a/tests/test_models.py b/tests/test_models.py index 96afc79..5e51c1d 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from copy import deepcopy -from unittest import mock from django.conf import settings from django.core.cache import caches