diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 314b3fc31a..2f914ce14a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -10,6 +10,7 @@ Changelog * Improved diffing behavior for text fields (Aliosha Padovani) * Improve contrast of disabled inputs (Nick Smith) * Added ``get_document_model_string`` function (Andrey Smirnov) + * Added support for Cloudflare API tokens for frontend cache invalidation (Tom Usher) * Fix: Rename documents listing column 'uploaded' to 'created' (LB (Ben Johnston)) * Fix: Submenu items longer then the page height are no longer broken by the submenu footer (Igor van Spengen) * Fix: Unbundle the l18n library as it was bundled to avoid installation errors which have been resolved (Matt Westcott) diff --git a/docs/reference/contrib/frontendcache.rst b/docs/reference/contrib/frontendcache.rst index 6238ae26e8..8cc9aa89d9 100644 --- a/docs/reference/contrib/frontendcache.rst +++ b/docs/reference/contrib/frontendcache.rst @@ -57,10 +57,17 @@ Cloudflare Firstly, you need to register an account with Cloudflare if you haven't already got one. You can do this here: `Cloudflare Sign up `_ -Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.CloudflareBackend``. This backend requires three extra parameters, ``EMAIL`` (your Cloudflare account email), ``TOKEN`` (your API token from Cloudflare), and ``ZONEID`` (for zone id for your domain, see below). +Add an item into the ``WAGTAILFRONTENDCACHE`` and set the ``BACKEND`` parameter to ``wagtail.contrib.frontend_cache.backends.CloudflareBackend``. -To find the ``ZONEID`` for your domain, read the `Cloudflare API Documentation `_ +This backend can be configured to use an account-wide API key, or an API token with restricted access. +To use an account-wide API key, find the key `as described in the Cloudflare documentation `_ and specify ``EMAIL`` and ``API_KEY`` parameters. + +To use a limited API token, `create a token `_ configured with the 'Zone, Cache Purge' permission and specify the ``BEARER_TOKEN`` parameter. + +A ``ZONEID`` parameter will need to be set for either option. To find the ``ZONEID`` for your domain, read the `Cloudflare API Documentation `_ + +With an API key: .. code-block:: python @@ -70,7 +77,21 @@ To find the ``ZONEID`` for your domain, read the `Cloudflare API Documentation < 'cloudflare': { 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', 'EMAIL': 'your-cloudflare-email-address@example.com', - 'TOKEN': 'your cloudflare api token', + 'API_KEY': 'your cloudflare api key', + 'ZONEID': 'your cloudflare domain zone id', + }, + } + +With an API token: + +.. code-block:: python + + # settings.py + + WAGTAILFRONTENDCACHE = { + 'cloudflare': { + 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', + 'BEARER_TOKEN': 'your cloudflare bearer token', 'ZONEID': 'your cloudflare domain zone id', }, } diff --git a/wagtail/contrib/frontend_cache/backends.py b/wagtail/contrib/frontend_cache/backends.py index 281594d8af..ffbdcabc5a 100644 --- a/wagtail/contrib/frontend_cache/backends.py +++ b/wagtail/contrib/frontend_cache/backends.py @@ -67,19 +67,35 @@ class HTTPBackend(BaseBackend): class CloudflareBackend(BaseBackend): def __init__(self, params): - self.cloudflare_email = params.pop('EMAIL') - self.cloudflare_token = params.pop('TOKEN') - self.cloudflare_zoneid = params.pop('ZONEID') + self.cloudflare_email = params.pop("EMAIL", None) + self.cloudflare_api_key = ( + params.pop("TOKEN", None) + or params.pop("API_KEY", None) + ) + self.cloudflare_token = params.pop("BEARER_TOKEN", None) + self.cloudflare_zoneid = params.pop("ZONEID") + + if ( + (not self.cloudflare_email and self.cloudflare_api_key) + or (self.cloudflare_email and not self.cloudflare_api_key) + or (not any([self.cloudflare_email, self.cloudflare_api_key, self.cloudflare_token])) + ): + raise ImproperlyConfigured( + "The setting 'WAGTAILFRONTENDCACHE' requires both 'EMAIL' and 'API_KEY', or 'BEARER_TOKEN' to be specified." + ) + def purge_batch(self, urls): try: purge_url = 'https://api.cloudflare.com/client/v4/zones/{0}/purge_cache'.format(self.cloudflare_zoneid) - headers = { - "X-Auth-Email": self.cloudflare_email, - "X-Auth-Key": self.cloudflare_token, - "Content-Type": "application/json", - } + headers = {"Content-Type": "application/json"} + + if self.cloudflare_token: + headers["Authorization"] = "Bearer {}".format(self.cloudflare_token) + else: + headers["X-Auth-Email"] = self.cloudflare_email + headers["X-Auth-Key"] = self.cloudflare_api_key data = {"files": urls} diff --git a/wagtail/contrib/frontend_cache/tests.py b/wagtail/contrib/frontend_cache/tests.py index 5bebdc02b7..e1602b9681 100644 --- a/wagtail/contrib/frontend_cache/tests.py +++ b/wagtail/contrib/frontend_cache/tests.py @@ -42,8 +42,9 @@ class TestBackendConfiguration(TestCase): 'cloudflare': { 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', 'EMAIL': 'test@test.com', - 'TOKEN': 'this is the token', + 'API_KEY': 'this is the api key', 'ZONEID': 'this is a zone id', + 'BEARER_TOKEN': 'this is a bearer token' }, }) @@ -51,7 +52,8 @@ class TestBackendConfiguration(TestCase): self.assertIsInstance(backends['cloudflare'], CloudflareBackend) self.assertEqual(backends['cloudflare'].cloudflare_email, 'test@test.com') - self.assertEqual(backends['cloudflare'].cloudflare_token, 'this is the token') + self.assertEqual(backends['cloudflare'].cloudflare_api_key, 'this is the api key') + self.assertEqual(backends['cloudflare'].cloudflare_token, 'this is a bearer token') def test_cloudfront(self): backends = get_backends(backend_settings={ @@ -152,7 +154,7 @@ class TestBackendConfiguration(TestCase): 'cloudflare': { 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', 'EMAIL': 'test@test.com', - 'TOKEN': 'this is the token', + 'API_KEY': 'this is the api key', 'ZONEID': 'this is a zone id', } }) @@ -168,7 +170,7 @@ class TestBackendConfiguration(TestCase): 'cloudflare': { 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', 'EMAIL': 'test@test.com', - 'TOKEN': 'this is the token', + 'API_KEY': 'this is the api key', 'ZONEID': 'this is a zone id', } }, backends=['cloudflare']) @@ -327,7 +329,7 @@ class TestPurgeBatchClass(TestCase): 'cloudflare': { 'BACKEND': 'wagtail.contrib.frontend_cache.backends.CloudflareBackend', 'EMAIL': 'test@test.com', - 'TOKEN': 'this is the token', + 'API_KEY': 'this is the api key', 'ZONEID': 'this is a zone id', }, }