From b8460b0acd3e833b9ec302d9fa3fb6ab28032c0e Mon Sep 17 00:00:00 2001 From: Michael Manfre Date: Tue, 6 Dec 2022 00:23:07 -0500 Subject: Only cache unauthenticated page views (#117) --- core/decorators.py | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'core/decorators.py') diff --git a/core/decorators.py b/core/decorators.py index fece564..dc8d4d2 100644 --- a/core/decorators.py +++ b/core/decorators.py @@ -1,34 +1,72 @@ +from collections.abc import Callable from functools import partial, wraps +from typing import ParamSpecArgs, ParamSpecKwargs +from django.http import HttpRequest from django.views.decorators.cache import cache_page as dj_cache_page from core.models import Config +VaryByFunc = Callable[[HttpRequest, ParamSpecArgs, ParamSpecKwargs], str] + + +def vary_by_ap_json(request, *args, **kwargs) -> str: + """ + Return a cache usable string token that is different based upon Accept + header. + """ + if request.ap_json: + return "ap_json" + return "not_ap" + + +def vary_by_identity(request, *args, **kwargs) -> str: + """ + Return a cache usable string token that is different based upon the + request.identity + """ + if request.identity: + return f"ident{request.identity.pk}" + return "identNone" + def cache_page( timeout: int | str = "cache_timeout_page_default", *, - per_identity: bool = False, key_prefix: str = "", + public_only: bool = False, + vary_by: VaryByFunc | list[VaryByFunc] | None = None, ): """ Decorator for views that caches the page result. timeout can either be the number of seconds or the name of a SystemOptions value. + If public_only is True, requests with an identity are not cached. """ _timeout = timeout + _prefix = key_prefix + if callable(vary_by): + vary_by = [vary_by] def decorator(function): @wraps(function) def inner(request, *args, **kwargs): - prefix = key_prefix - if per_identity: - identity_id = request.identity.pk if request.identity else "0" - prefix = f"{key_prefix or ''}:ident{identity_id}" + if public_only: + if request.user.is_authenticated: + return function(request, *args, **kwargs) + + prefix = [_prefix] + + if isinstance(vary_by, list): + prefix.extend([vfunc(request, *args, **kwargs) for vfunc in vary_by]) + + prefix = "".join(prefix) + if isinstance(_timeout, str): timeout = getattr(Config.system, _timeout) else: timeout = _timeout + return dj_cache_page(timeout=timeout, key_prefix=prefix)(function)( request, *args, **kwargs ) @@ -38,4 +76,4 @@ def cache_page( return decorator -per_identity_cache_page = partial(cache_page, per_identity=True) +cache_page_by_ap_json = partial(cache_page, vary_by=[vary_by_ap_json]) -- cgit v1.2.3