django-commons/django-cookie-consent

Add Signal For Clearing Cache When Cookie Model Updates

Closed this issue · 1 comments

If the django admin updates the Cookie model with new third party cookies, there should be a way to delete the cache with the old cookies and then set the cache with the newly added cookies.

I made a separate django project based off the django-cookie-consent library that does this. The code is somewhat different though. Not sure when I will have time to make a PR for the django-cookie-consent that implements this feature but here is what I did below in that other project in case someone wants to make a PR. It has been a while since I wrote this code so I apologize for the mess - especially in the middleware file (but the middleware file below only queries off the cache rather than the database).

We may need to account for people who do not want to use the cache and for people who want to use the database for the middleware with a setting.

Models.py:

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.cache import cache
from django.conf import settings

#If the Cookie model updates, delete the cookie_consent key in the cache. This is used for middleware to update the cached template tag query with updated cookies.
@receiver(post_save, sender=Cookie)
def clear_cache(sender, instance, **kwargs):
    cache.delete(settings.COOKIE_CONSENT_NAME)

Template:

{% cookie_cache_tag request %}

cookie_consent_tags.py:

from django import template
from django.conf import settings
from cookie_consent.models import CookieGroup, Cookie, CookieType
from django.core.cache import cache

register = template.Library()

@register.simple_tag
def cookie_cache_tag(request):
    items = cache.get(settings.COOKIE_CONSENT_NAME)
    if items is None:
        qs = CookieGroup.objects.filter(is_required=False) #get all third party cookie groups. Maybe add is_deletable=True to this
        qs = qs.prefetch_related('cookie_set') 
        #items = dict([(g.name, g) for g in qs])
        items = {g.name: g for g in qs}
        #print(qs.values())
        cache.set(settings.COOKIE_CONSENT_NAME, items, settings.COOKIE_CONSENT_MAX_AGE)
    return '' #return nothing for the template tag, otherwise it will set the cookie_consent cache key

Middleware:

    """
    #This code works but does not use cache
    def process_response(self, request, response):
        #Remove all third party cookies when there is no consent cookie
        if request.COOKIES.get('cookie_consent', None) is None:
            for x in CookieGroup.objects.filter(is_required=0).values_list('name',flat='true'):
                for y in Cookie.objects.filter(cookiegroup__name=x).values_list('name',flat='true'):
                    response.delete_cookie(y)
        #Remove all third party cookies when there are declined consent cookie values
        if request.COOKIES.get('cookie_consent', None) is not None:
            dic = {}
            for c in request.COOKIES.get('cookie_consent', '').split("|"):
                key, value = c.split("=")
                dic[key] = value
            for k, v in dic.items():
                if v == '0':
                    declined_cookie_groups = k
                    for x in Cookie.objects.filter(cookiegroup__name=declined_cookie_groups).values_list('name',flat='true'):
                        response.delete_cookie(x)
        return response
    """

    def process_response(self, request, response):

        """
        if cache.get(settings.COOKIE_CONSENT_NAME): #check for cookie_consent key in redis
            cookie_consent_cache_dic = cache.get(settings.COOKIE_CONSENT_NAME).values()
            list(cache.get(settings.COOKIE_CONSENT_NAME).values())  # [<CookieGroup: Group2>, <CookieGroup: Group3>]
            print(list(cache.get(settings.COOKIE_CONSENT_NAME).values()))
            for z in list(cache.get(settings.COOKIE_CONSENT_NAME).values()):
                print(z) #z.COOKIE_GROUP_MODEL_FIELD_NAME
        """

        #Remove all third party cookies when there is no consent cookie
        if request.COOKIES.get(settings.COOKIE_CONSENT_NAME, None) is None: #get cookie_consent cookie from browser
            if cache.get(settings.COOKIE_CONSENT_NAME): #check for cookie_consent key in redis
                cookie_consent_cache_dic = cache.get(settings.COOKIE_CONSENT_NAME).values() #dict_values([<CookieGroup: Group2>, <CookieGroup: Group3>])
                for x in cookie_consent_cache_dic: #Loop through group model. x.COOKIE_GROUP_MODEL_FIELD_NAME becomes accessible in this loop.
                    for y in x.cookie_set.all(): #Loop through y.COOKIE_MODEL_FIELD_NAME from the cache query - <QuerySet [<Cookie: third_party_cookie_name 127.0.0.1:8000/>]> - cookie_set comes from the template tag
                        if y.name not in request.COOKIES.keys(): #if COOKIE_MODEL_FIELD_NAME not in the browser cookies - not sure if I need this check or not
                            continue
                        response.delete_cookie(y.name, path=y.path, domain=y.domain)
        #Remove all third party cookies when there are declined consent cookie values
        if request.COOKIES.get(settings.COOKIE_CONSENT_NAME, None) is not None:
            dic = {}
            for c in request.COOKIES.get(settings.COOKIE_CONSENT_NAME, '').split("|"):
                key, value = c.split("=")
                dic[key] = value
            for k, v in dic.items():
                if v == '0':
                    declined_cookie_groups = k
                    if cache.get(settings.COOKIE_CONSENT_NAME):
                        cookie_consent_cache_dic = cache.get(settings.COOKIE_CONSENT_NAME).values()
                        for x in cookie_consent_cache_dic:
                            if x.name == declined_cookie_groups:
                                for y in x.cookie_set.all():
                                    if y.name not in request.COOKIES.keys(): #if COOKIE_MODEL_FIELD_NAME not in the browser cookies - not sure if I need this check or not
                                        continue
                                    response.delete_cookie(y.name, y.path, y.domain)
        return response