# === core/context_processors.py === # Globals injected into every template render. # # `deployment_timestamp` is a cache-bust token on our CSS URL. Historically # it was `int(time.time())` — a new value every second — which defeated # Cloudflare's edge cache because every page load saw a different `?v=...` # string. We now tie the token to `custom.css`'s mtime, so the URL # changes ONLY when the CSS actually changes. Cloudflare can hold the # file for its full 4h TTL, and users on repeat visits hit the browser # cache (304 Not Modified). import os import time from pathlib import Path from django.conf import settings # Path to the file whose mtime drives the cache-bust token. Module-level # constant so tests can monkey-patch it to simulate "file missing". _CSS_PATH_FOR_TOKEN = Path(settings.BASE_DIR) / 'static' / 'css' / 'custom.css' def _compute_cache_bust_token(): """Return an integer cache-bust token. Normal path: returns the CSS file's mtime (an integer). Fallback: if the file can't be stat'd (doesn't exist / permission error / disk issue), returns the current wall-clock time in seconds — that degrades to the PRE-FIX behaviour (new token per request) rather than crashing the whole request cycle. """ try: return int(os.path.getmtime(_CSS_PATH_FOR_TOKEN)) except (OSError, FileNotFoundError): return int(time.time()) def project_context(request): """Adds project-specific environment variables to the template context globally.""" return { "project_description": os.getenv("PROJECT_DESCRIPTION", ""), "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), # Cache-busts static assets — see _compute_cache_bust_token(). "deployment_timestamp": _compute_cache_bust_token(), }